Compare commits

...

19 Commits

Author SHA1 Message Date
vladimir.kuznetsov 44018ec94c Merge branch 'dev' of github.com:amnezia-vpn/amnezia-client into feature/v2ray-container 2023-04-08 18:14:52 +03:00
vladimir.kuznetsov 89577651d6 fixed V2RayKeyMissing error handling 2023-03-27 08:37:28 +03:00
vladimir.kuznetsov 3b2d3a0b34 Merge branch 'dev' of github.com:amnezia-vpn/desktop-client into feature/v2ray-container 2023-03-19 14:40:30 +03:00
vladimir.kuznetsov fe3228ed74 Merge branch 'dev' of github.com:amnezia-vpn/desktop-client into feature/v2ray-container 2023-02-28 05:34:34 +03:00
vladimir.kuznetsov 917942be94 Merge branch 'dev' of github.com:amnezia-vpn/desktop-client into feature/v2ray-container 2023-02-27 19:51:26 +03:00
vladimir.kuznetsov 6a3875ec7f Merge branch 'dev' of github.com:amnezia-vpn/desktop-client into feature/v2ray-container 2023-02-24 17:54:09 +03:00
vladimir.kuznetsov e121ca9b53 added v2ray binaries for macos and linux 2023-02-15 18:27:00 +03:00
vladimir.kuznetsov c23c8e8462 changed the way shadowsocks client config was created
- some code style refactoring
2023-02-14 19:46:08 +03:00
vladimir.kuznetsov 36fae9152f added local port field to v2ray settings page
- some code style refactoring
2023-02-14 08:35:03 +03:00
vladimir.kuznetsov 2b0ba2aff9 added settings page for v2ray 2023-02-13 18:17:42 +03:00
vladimir.kuznetsov 68830021d6 changed v2ray client config generation 2023-02-13 10:05:15 +03:00
vladimir.kuznetsov 6a903792ab Merge branch 'dev' of github.com:amnezia-vpn/desktop-client into feature/v2ray-container 2023-02-13 07:48:47 +03:00
vladimir.kuznetsov d2d9c33837 Merge branch 'feature/v2ray-container' of github.com:amnezia-vpn/desktop-client into feature/v2ray-container 2023-02-10 20:07:33 +03:00
vladimir.kuznetsov 7d51cb7d58 added implementation of V2RayConfigurator and V2RayProtocol classes 2023-02-10 20:07:17 +03:00
Alexander Gertovskiy 7df3600a62 v2ray-container: added server scripts to start openvpn with v2ray.
* fixed client/server_scripts/openvpn_v2ray_vmess/template_v2ray_client.json
2023-02-09 23:14:34 +02:00
Alexander Gertovskiy 634ca6cbe8 v2ray-container: added server scripts to start openvpn with v2ray.
* added client/server_scripts/openvpn_v2ray_vmess/template_v2ray_client.json
* fixed client/server_scripts/openvpn_v2ray_vmess/template.ovpn
2023-02-09 23:00:14 +02:00
vladimir.kuznetsov 8032e55d7c added a template for the v2ray protocol 2023-02-09 12:41:10 +03:00
Alexander Gertovskiy dc2a1467c7 v2ray-container: added server scripts to start openvpn with v2ray. 2023-02-08 19:00:51 +02:00
Alexander Gertovskiy 67c36f5b30 v2ray-container: added server scripts to start openvpn with v2ray. 2023-02-08 17:48:27 +02:00
56 changed files with 998 additions and 192 deletions
+3 -1
View File
@@ -235,6 +235,7 @@ if(WIN32 OR (APPLE AND NOT IOS) OR (LINUX AND NOT ANDROID))
${CMAKE_CURRENT_LIST_DIR}/protocols/openvpnovercloakprotocol.h
${CMAKE_CURRENT_LIST_DIR}/protocols/shadowsocksvpnprotocol.h
${CMAKE_CURRENT_LIST_DIR}/protocols/wireguardprotocol.h
${CMAKE_CURRENT_LIST_DIR}/protocols/v2rayprotocol.h
)
set(SOURCES ${SOURCES}
@@ -245,6 +246,7 @@ if(WIN32 OR (APPLE AND NOT IOS) OR (LINUX AND NOT ANDROID))
${CMAKE_CURRENT_LIST_DIR}/protocols/openvpnovercloakprotocol.cpp
${CMAKE_CURRENT_LIST_DIR}/protocols/shadowsocksvpnprotocol.cpp
${CMAKE_CURRENT_LIST_DIR}/protocols/wireguardprotocol.cpp
${CMAKE_CURRENT_LIST_DIR}/protocols/v2rayprotocol.cpp
)
endif()
@@ -558,7 +560,7 @@ if(WIN32)
set(DEPLOY_ARTIFACT_PATH "windows/x32")
endif()
elseif(LINUX)
set(DEPLOY_ARTIFACT_PATH "linux/client")
set(DEPLOY_ARTIFACT_PATH "linux/client/bin")
elseif(APPLE AND NOT IOS)
set(DEPLOY_ARTIFACT_PATH "macos")
endif()
+7 -7
View File
@@ -7,24 +7,24 @@
#include "core/servercontroller.h"
#include "containers/containers_defs.h"
CloakConfigurator::CloakConfigurator(std::shared_ptr<Settings> settings, QObject *parent):
ConfiguratorBase(settings, parent)
CloakConfigurator::CloakConfigurator(std::shared_ptr<Settings> settings,
QObject *parent): ConfiguratorBase(settings, parent)
{
}
QString CloakConfigurator::genCloakConfig(const ServerCredentials &credentials,
DockerContainer container, const QJsonObject &containerConfig, ErrorCode *errorCode)
QString CloakConfigurator::genCloakConfig(const ServerCredentials &credentials, DockerContainer container,
const QJsonObject &containerConfig, ErrorCode *errorCode)
{
ErrorCode e = ErrorCode::NoError;
ServerController serverController(m_settings);
QString cloakPublicKey = serverController.getTextFileFromContainer(container, credentials,
amnezia::protocols::cloak::ckPublicKeyPath, &e);
amnezia::protocols::cloak::ckPublicKeyPath, &e);
cloakPublicKey.replace("\n", "");
QString cloakBypassUid = serverController.getTextFileFromContainer(container, credentials,
amnezia::protocols::cloak::ckBypassUidKeyPath, &e);
amnezia::protocols::cloak::ckBypassUidKeyPath, &e);
cloakBypassUid.replace("\n", "");
if (e) {
+1 -1
View File
@@ -14,7 +14,7 @@ public:
CloakConfigurator(std::shared_ptr<Settings> settings, QObject *parent = nullptr);
QString genCloakConfig(const ServerCredentials &credentials, DockerContainer container,
const QJsonObject &containerConfig, ErrorCode *errorCode = nullptr);
const QJsonObject &containerConfig, ErrorCode *errorCode = nullptr);
};
#endif // CLOAK_CONFIGURATOR_H
+2 -4
View File
@@ -1,8 +1,6 @@
#include "configurator_base.h"
ConfiguratorBase::ConfiguratorBase(std::shared_ptr<Settings> settings, QObject *parent)
: QObject{parent},
m_settings(settings)
ConfiguratorBase::ConfiguratorBase(std::shared_ptr<Settings> settings,
QObject *parent): QObject{parent}, m_settings(settings)
{
}
+13 -16
View File
@@ -1,4 +1,5 @@
#include "ikev2_configurator.h"
#include <QApplication>
#include <QProcess>
#include <QString>
@@ -15,14 +16,13 @@
#include "core/servercontroller.h"
Ikev2Configurator::Ikev2Configurator(std::shared_ptr<Settings> settings, QObject *parent):
ConfiguratorBase(settings, parent)
Ikev2Configurator::Ikev2Configurator(std::shared_ptr<Settings> settings,
QObject *parent): ConfiguratorBase(settings, parent)
{
}
Ikev2Configurator::ConnectionData Ikev2Configurator::prepareIkev2Config(const ServerCredentials &credentials,
DockerContainer container, ErrorCode *errorCode)
DockerContainer container, ErrorCode *errorCode)
{
Ikev2Configurator::ConnectionData connData;
connData.host = credentials.hostName;
@@ -33,21 +33,18 @@ Ikev2Configurator::ConnectionData Ikev2Configurator::prepareIkev2Config(const Se
QString certFileName = "/opt/amnezia/ikev2/clients/" + connData.clientId + ".p12";
QString scriptCreateCert = QString("certutil -z <(head -c 1024 /dev/urandom) "\
"-S -c \"IKEv2 VPN CA\" -n \"%1\" "\
"-s \"O=IKEv2 VPN,CN=%1\" "\
"-k rsa -g 3072 -v 120 "\
"-d sql:/etc/ipsec.d -t \",,\" "\
"--keyUsage digitalSignature,keyEncipherment "\
"--extKeyUsage serverAuth,clientAuth -8 \"%1\"")
.arg(connData.clientId);
"-S -c \"IKEv2 VPN CA\" -n \"%1\" "\
"-s \"O=IKEv2 VPN,CN=%1\" "\
"-k rsa -g 3072 -v 120 "\
"-d sql:/etc/ipsec.d -t \",,\" "\
"--keyUsage digitalSignature,keyEncipherment "\
"--extKeyUsage serverAuth,clientAuth -8 \"%1\"").arg(connData.clientId);
ServerController serverController(m_settings);
ErrorCode e = serverController.runContainerScript(credentials, container, scriptCreateCert);
QString scriptExportCert = QString("pk12util -W \"%1\" -d sql:/etc/ipsec.d -n \"%2\" -o \"%3\"")
.arg(connData.password)
.arg(connData.clientId)
.arg(certFileName);
.arg(connData.password, connData.clientId, certFileName);
e = serverController.runContainerScript(credentials, container, scriptExportCert);
connData.clientCert = serverController.getTextFileFromContainer(container, credentials, certFileName, &e);
@@ -59,8 +56,8 @@ Ikev2Configurator::ConnectionData Ikev2Configurator::prepareIkev2Config(const Se
return connData;
}
QString Ikev2Configurator::genIkev2Config(const ServerCredentials &credentials,
DockerContainer container, const QJsonObject &containerConfig, ErrorCode *errorCode)
QString Ikev2Configurator::genIkev2Config(const ServerCredentials &credentials, DockerContainer container,
const QJsonObject &containerConfig, ErrorCode *errorCode)
{
Q_UNUSED(containerConfig)
+3 -3
View File
@@ -22,14 +22,14 @@ public:
};
QString genIkev2Config(const ServerCredentials &credentials, DockerContainer container,
const QJsonObject &containerConfig, ErrorCode *errorCode = nullptr);
const QJsonObject &containerConfig, ErrorCode *errorCode = nullptr);
QString genIkev2Config(const ConnectionData &connData);
QString genMobileConfig(const ConnectionData &connData);
QString genStrongSwanConfig(const ConnectionData &connData);
ConnectionData prepareIkev2Config(const ServerCredentials &credentials,
DockerContainer container, ErrorCode *errorCode = nullptr);
ConnectionData prepareIkev2Config(const ServerCredentials &credentials, DockerContainer container,
ErrorCode *errorCode = nullptr);
};
#endif // IKEV2_CONFIGURATOR_H
+28 -32
View File
@@ -1,4 +1,5 @@
#include "openvpn_configurator.h"
#include <QApplication>
#include <QProcess>
#include <QString>
@@ -19,14 +20,13 @@
#include <openssl/x509.h>
#include <openssl/pem.h>
OpenVpnConfigurator::OpenVpnConfigurator(std::shared_ptr<Settings> settings, QObject *parent):
ConfiguratorBase(settings, parent)
OpenVpnConfigurator::OpenVpnConfigurator(std::shared_ptr<Settings> settings,
QObject *parent): ConfiguratorBase(settings, parent)
{
}
OpenVpnConfigurator::ConnectionData OpenVpnConfigurator::prepareOpenVpnConfig(const ServerCredentials &credentials,
DockerContainer container, ErrorCode *errorCode)
DockerContainer container, ErrorCode *errorCode)
{
OpenVpnConfigurator::ConnectionData connData = OpenVpnConfigurator::createCertRequest();
connData.host = credentials.hostName;
@@ -36,9 +36,7 @@ OpenVpnConfigurator::ConnectionData OpenVpnConfigurator::prepareOpenVpnConfig(co
return connData;
}
QString reqFileName = QString("%1/%2.req").
arg(amnezia::protocols::openvpn::clientsDirPath).
arg(connData.clientId);
QString reqFileName = QString("%1/%2.req").arg(amnezia::protocols::openvpn::clientsDirPath, connData.clientId);
ServerController serverController(m_settings);
ErrorCode e = serverController.uploadTextFileToContainer(container, credentials, connData.request, reqFileName);
@@ -53,9 +51,11 @@ OpenVpnConfigurator::ConnectionData OpenVpnConfigurator::prepareOpenVpnConfig(co
return connData;
}
connData.caCert = serverController.getTextFileFromContainer(container, credentials, amnezia::protocols::openvpn::caCertPath, &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);
QString("%1/%2.crt").arg(amnezia::protocols::openvpn::clientCertPath, connData.clientId),
&e);
if (e) {
if (errorCode) *errorCode = e;
@@ -71,12 +71,12 @@ OpenVpnConfigurator::ConnectionData OpenVpnConfigurator::prepareOpenVpnConfig(co
return connData;
}
QString OpenVpnConfigurator::genOpenVpnConfig(const ServerCredentials &credentials,
DockerContainer container, const QJsonObject &containerConfig, ErrorCode *errorCode)
QString OpenVpnConfigurator::genOpenVpnConfig(const ServerCredentials &credentials, DockerContainer container,
const QJsonObject &containerConfig, ErrorCode *errorCode)
{
ServerController serverController(m_settings);
QString config = serverController.replaceVars(amnezia::scriptData(ProtocolScriptType::openvpn_template, container),
serverController.genVarsForScript(credentials, container, containerConfig));
serverController.genVarsForScript(credentials, container, containerConfig));
ConnectionData connData = prepareOpenVpnConfig(credentials, container, errorCode);
if (errorCode && *errorCode) {
@@ -89,8 +89,7 @@ QString OpenVpnConfigurator::genOpenVpnConfig(const ServerCredentials &credentia
if (config.contains("$OPENVPN_TA_KEY")) {
config.replace("$OPENVPN_TA_KEY", connData.taKey);
}
else {
} else {
config.replace("<tls-auth>", "");
config.replace("</tls-auth>", "");
}
@@ -112,8 +111,7 @@ QString OpenVpnConfigurator::processConfigWithLocalSettings(QString jsonConfig)
if (m_settings->routeMode() != Settings::VpnAllSites) {
config.replace("redirect-gateway def1 bypass-dhcp", "");
}
else {
} else {
if(!config.contains("redirect-gateway def1 bypass-dhcp")) {
config.append("redirect-gateway def1 bypass-dhcp\n");
}
@@ -151,23 +149,22 @@ QString OpenVpnConfigurator::processConfigWithExportSettings(QString jsonConfig)
return QJsonDocument(json).toJson();
}
ErrorCode OpenVpnConfigurator::signCert(DockerContainer container,
const ServerCredentials &credentials, QString clientId)
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(ContainerProps::containerToString(container))
.arg(amnezia::protocols::openvpn::clientsDirPath)
.arg(clientId);
"easyrsa import-req %2/%3.req %3\"")
.arg(ContainerProps::containerToString(container),
amnezia::protocols::openvpn::clientsDirPath,
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(ContainerProps::containerToString(container))
.arg(clientId);
"easyrsa sign-req client %2\"")
.arg(ContainerProps::containerToString(container), clientId);
ServerController serverController(m_settings);
QStringList scriptList {script_import, script_sign};
QString script = serverController.replaceVars(scriptList.join("\n"), serverController.genVarsForScript(credentials, container));
QString script = serverController.replaceVars(scriptList.join("\n"),
serverController.genVarsForScript(credentials, container));
return serverController.runScript(credentials, script);
}
@@ -177,8 +174,8 @@ OpenVpnConfigurator::ConnectionData OpenVpnConfigurator::createCertRequest()
ConnectionData connData;
connData.clientId = Utils::getRandomString(32);
int ret = 0;
int nVersion = 1;
int ret = 0;
int nVersion = 1;
QByteArray clientIdUtf8 = connData.clientId.toUtf8();
@@ -211,7 +208,7 @@ OpenVpnConfigurator::ConnectionData OpenVpnConfigurator::createCertRequest()
// 4. set public key of x509 req
ret = X509_REQ_set_pubkey(x509_req, pKey);
if (ret != 1){
if (ret != 1) {
qWarning() << "Could not set pubkey!";
X509_REQ_free(x509_req);
EVP_PKEY_free(pKey);
@@ -220,7 +217,7 @@ OpenVpnConfigurator::ConnectionData OpenVpnConfigurator::createCertRequest()
// 5. set sign key of x509 req
ret = X509_REQ_sign(x509_req, pKey, EVP_sha256()); // return x509_req->signature->length
if (ret <= 0){
if (ret <= 0) {
qWarning() << "Could not sign request!";
X509_REQ_free(x509_req);
EVP_PKEY_free(pKey);
@@ -230,8 +227,7 @@ OpenVpnConfigurator::ConnectionData OpenVpnConfigurator::createCertRequest()
// save private key
BIO * bp_private = BIO_new(BIO_s_mem());
q_check_ptr(bp_private);
if (PEM_write_bio_PrivateKey(bp_private, pKey, nullptr, nullptr, 0, nullptr, nullptr) != 1)
{
if (PEM_write_bio_PrivateKey(bp_private, pKey, nullptr, nullptr, 0, nullptr, nullptr) != 1) {
qFatal("PEM_write_bio_PrivateKey");
EVP_PKEY_free(pKey);
BIO_free_all(bp_private);
+4 -6
View File
@@ -24,20 +24,18 @@ public:
};
QString genOpenVpnConfig(const ServerCredentials &credentials, DockerContainer container,
const QJsonObject &containerConfig, ErrorCode *errorCode = nullptr);
const QJsonObject &containerConfig, ErrorCode *errorCode = nullptr);
QString processConfigWithLocalSettings(QString jsonConfig);
QString processConfigWithExportSettings(QString jsonConfig);
ErrorCode signCert(DockerContainer container,
const ServerCredentials &credentials, QString clientId);
ErrorCode signCert(DockerContainer container, const ServerCredentials &credentials, QString clientId);
private:
ConnectionData createCertRequest();
ConnectionData prepareOpenVpnConfig(const ServerCredentials &credentials,
DockerContainer container, ErrorCode *errorCode = nullptr);
ConnectionData prepareOpenVpnConfig(const ServerCredentials &credentials, DockerContainer container,
ErrorCode *errorCode = nullptr);
};
#endif // OPENVPN_CONFIGURATOR_H
@@ -5,16 +5,16 @@
#include <QJsonDocument>
#include "containers/containers_defs.h"
#include "core/scripts_registry.h"
#include "core/servercontroller.h"
ShadowSocksConfigurator::ShadowSocksConfigurator(std::shared_ptr<Settings> settings, QObject *parent):
ConfiguratorBase(settings, parent)
ShadowSocksConfigurator::ShadowSocksConfigurator(std::shared_ptr<Settings> settings,
QObject *parent): ConfiguratorBase(settings, parent)
{
}
QString ShadowSocksConfigurator::genShadowSocksConfig(const ServerCredentials &credentials,
DockerContainer container, const QJsonObject &containerConfig, ErrorCode *errorCode)
QString ShadowSocksConfigurator::genShadowSocksConfig(const ServerCredentials &credentials, DockerContainer container,
const QJsonObject &containerConfig, ErrorCode *errorCode)
{
ErrorCode e = ErrorCode::NoError;
ServerController serverController(m_settings);
@@ -28,18 +28,12 @@ QString ShadowSocksConfigurator::genShadowSocksConfig(const ServerCredentials &c
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 ssClientConfig = serverController.replaceVars(amnezia::scriptData(ProtocolScriptType::shadowsocks_client_template, container),
serverController.genVarsForScript(credentials, container, containerConfig));
QString textCfg = serverController.replaceVars(QJsonDocument(config).toJson(),
serverController.genVarsForScript(credentials, container, containerConfig));
ssClientConfig.replace("$SHADOWSOCKS_PASSWORD", ssKey);
ssClientConfig = serverController.replaceVars(ssClientConfig, serverController.genVarsForScript(credentials, container, containerConfig));
//qDebug().noquote() << textCfg;
return textCfg;
return ssClientConfig;
}
@@ -13,7 +13,7 @@ public:
ShadowSocksConfigurator(std::shared_ptr<Settings> settings, QObject *parent = nullptr);
QString genShadowSocksConfig(const ServerCredentials &credentials, DockerContainer container,
const QJsonObject &containerConfig, ErrorCode *errorCode = nullptr);
const QJsonObject &containerConfig, ErrorCode *errorCode = nullptr);
};
#endif // SHADOWSOCKS_CONFIGURATOR_H
+5 -8
View File
@@ -1,4 +1,5 @@
#include "ssh_configurator.h"
#include <QApplication>
#include <QProcess>
#include <QString>
@@ -14,11 +15,9 @@
#include "core/server_defs.h"
#include "utilities.h"
SshConfigurator::SshConfigurator(std::shared_ptr<Settings> settings, QObject *parent):
ConfiguratorBase(settings, parent)
SshConfigurator::SshConfigurator(std::shared_ptr<Settings> settings,
QObject *parent): ConfiguratorBase(settings, parent)
{
}
QString SshConfigurator::convertOpenSShKey(const QString &key)
@@ -73,10 +72,8 @@ void SshConfigurator::openSshTerminal(const ServerCredentials &credentials)
// todo: connect by key
// p->setNativeArguments(QString("%1@%2")
// .arg(credentials.userName).arg(credentials.hostName).arg(credentials.password));
}
else {
p->setNativeArguments(QString("%1@%2 -pw %3")
.arg(credentials.userName).arg(credentials.hostName).arg(credentials.password));
} else {
p->setNativeArguments(QString("%1@%2 -pw %3").arg(credentials.userName).arg(credentials.hostName, credentials.password));
}
#else
p->setProgram("/bin/bash");
-1
View File
@@ -16,7 +16,6 @@ public:
QProcessEnvironment prepareEnv();
QString convertOpenSShKey(const QString &key);
void openSshTerminal(const ServerCredentials &credentials);
};
#endif // SSH_CONFIGURATOR_H
@@ -0,0 +1,46 @@
#include "v2ray_configurator.h"
#include <QFile>
#include <QPair>
#include <QJsonArray>
#include <QJsonObject>
#include <QJsonDocument>
#include "core/servercontroller.h"
#include "core/scripts_registry.h"
#include "containers/containers_defs.h"
V2RayConfigurator::V2RayConfigurator(std::shared_ptr<Settings> settings,
QObject *parent) : ConfiguratorBase(settings, parent)
{
}
QString V2RayConfigurator::genV2RayConfig(const ServerCredentials &credentials, DockerContainer container,
const QJsonObject &containerConfig, ErrorCode *errorCode)
{
ErrorCode e = ErrorCode::NoError;
ServerController serverController(m_settings);
QString v2RayVmessClientUuid = serverController.getTextFileFromContainer(container, credentials,
amnezia::protocols::v2ray::v2rayKeyPath, &e);
if (v2RayVmessClientUuid.isEmpty()) {
if (errorCode) *errorCode = ErrorCode::V2RayKeyMissing;
return "";
}
v2RayVmessClientUuid.replace("\n", "");
if (e) {
if (errorCode) *errorCode = e;
return "";
}
QString v2RayClientConfig = serverController.replaceVars(amnezia::scriptData(ProtocolScriptType::v2ray_client_template, container),
serverController.genVarsForScript(credentials, container, containerConfig));
v2RayClientConfig.replace("$V2RAY_VMESS_CLIENT_UUID", v2RayVmessClientUuid);
v2RayClientConfig = serverController.replaceVars(v2RayClientConfig,
serverController.genVarsForScript(credentials, container, containerConfig));
return v2RayClientConfig;
}
+20
View File
@@ -0,0 +1,20 @@
#ifndef V2RAYCONFIGURATOR_H
#define V2RAYCONFIGURATOR_H
#include <QObject>
#include "configurator_base.h"
using namespace amnezia;
class V2RayConfigurator : ConfiguratorBase
{
public:
V2RayConfigurator(std::shared_ptr<Settings> settings, QObject *parent = nullptr);
QString genV2RayConfig(const ServerCredentials &credentials, DockerContainer container,
const QJsonObject &containerConfig, ErrorCode *errorCode = nullptr);
};
#endif // V2RAYCONFIGURATOR_H
+12 -18
View File
@@ -5,6 +5,7 @@
#include "wireguard_configurator.h"
#include "ikev2_configurator.h"
#include "ssh_configurator.h"
#include "v2ray_configurator.h"
#include <QFile>
#include <QJsonObject>
@@ -14,8 +15,8 @@
#include "utilities.h"
#include "settings.h"
VpnConfigurator::VpnConfigurator(std::shared_ptr<Settings> settings, QObject *parent):
ConfiguratorBase(settings, parent)
VpnConfigurator::VpnConfigurator(std::shared_ptr<Settings> settings,
QObject *parent) : ConfiguratorBase(settings, parent)
{
openVpnConfigurator = std::shared_ptr<OpenVpnConfigurator>(new OpenVpnConfigurator(settings, this));
shadowSocksConfigurator = std::shared_ptr<ShadowSocksConfigurator>(new ShadowSocksConfigurator(settings, this));
@@ -25,25 +26,22 @@ VpnConfigurator::VpnConfigurator(std::shared_ptr<Settings> settings, QObject *pa
sshConfigurator = std::shared_ptr<SshConfigurator>(new SshConfigurator(settings, this));
}
QString VpnConfigurator::genVpnProtocolConfig(const ServerCredentials &credentials,
DockerContainer container, const QJsonObject &containerConfig, Proto proto, ErrorCode *errorCode)
QString VpnConfigurator::genVpnProtocolConfig(const ServerCredentials &credentials, DockerContainer container,
const QJsonObject &containerConfig, Proto proto, ErrorCode *errorCode)
{
switch (proto) {
case Proto::OpenVpn:
return openVpnConfigurator->genOpenVpnConfig(credentials, container, containerConfig, errorCode);
case Proto::ShadowSocks:
return shadowSocksConfigurator->genShadowSocksConfig(credentials, container, containerConfig, errorCode);
case Proto::Cloak:
return cloakConfigurator->genCloakConfig(credentials, container, containerConfig, errorCode);
case Proto::WireGuard:
return wireguardConfigurator->genWireguardConfig(credentials, container, containerConfig, errorCode);
case Proto::Ikev2:
return ikev2Configurator->genIkev2Config(credentials, container, containerConfig, errorCode);
case Proto::V2Ray:
return v2RayConfigurator->genV2RayConfig(credentials, container, containerConfig, errorCode);
default:
return "";
}
@@ -62,8 +60,7 @@ QPair<QString, QString> VpnConfigurator::getDnsForConfig(int serverIndex)
if (dns.first.isEmpty() || !Utils::checkIPv4Format(dns.first)) {
if (useAmneziaDns && m_settings->containers(serverIndex).contains(DockerContainer::Dns)) {
dns.first = protocols::dns::amneziaDnsIp;
}
else dns.first = m_settings->primaryDns();
} else dns.first = m_settings->primaryDns();
}
if (dns.second.isEmpty() || !Utils::checkIPv4Format(dns.second)) {
dns.second = m_settings->secondaryDns();
@@ -73,8 +70,7 @@ QPair<QString, QString> VpnConfigurator::getDnsForConfig(int serverIndex)
return dns;
}
QString &VpnConfigurator::processConfigWithDnsSettings(int serverIndex, DockerContainer container,
Proto proto, QString &config)
QString &VpnConfigurator::processConfigWithDnsSettings(int serverIndex, DockerContainer container, Proto proto, QString &config)
{
auto dns = getDnsForConfig(serverIndex);
@@ -84,8 +80,7 @@ QString &VpnConfigurator::processConfigWithDnsSettings(int serverIndex, DockerCo
return config;
}
QString &VpnConfigurator::processConfigWithLocalSettings(int serverIndex, DockerContainer container,
Proto proto, QString &config)
QString &VpnConfigurator::processConfigWithLocalSettings(int serverIndex, DockerContainer container, Proto proto, QString &config)
{
processConfigWithDnsSettings(serverIndex, container, proto, config);
@@ -95,8 +90,7 @@ QString &VpnConfigurator::processConfigWithLocalSettings(int serverIndex, Docker
return config;
}
QString &VpnConfigurator::processConfigWithExportSettings(int serverIndex, DockerContainer container,
Proto proto, QString &config)
QString &VpnConfigurator::processConfigWithExportSettings(int serverIndex, DockerContainer container, Proto proto, QString &config)
{
processConfigWithDnsSettings(serverIndex, container, proto, config);
@@ -107,7 +101,7 @@ QString &VpnConfigurator::processConfigWithExportSettings(int serverIndex, Docke
}
void VpnConfigurator::updateContainerConfigAfterInstallation(DockerContainer container, QJsonObject &containerConfig,
const QString &stdOut)
const QString &stdOut)
{
Proto mainProto = ContainerProps::defaultProtocol(container);
+4 -3
View File
@@ -13,6 +13,7 @@ class CloakConfigurator;
class WireguardConfigurator;
class Ikev2Configurator;
class SshConfigurator;
class V2RayConfigurator;
// Retrieve connection settings from server
class VpnConfigurator : ConfiguratorBase
@@ -22,7 +23,7 @@ public:
VpnConfigurator(std::shared_ptr<Settings> settings, QObject *parent = nullptr);
QString genVpnProtocolConfig(const ServerCredentials &credentials, DockerContainer container,
const QJsonObject &containerConfig, Proto proto, ErrorCode *errorCode = nullptr);
const QJsonObject &containerConfig, Proto proto, ErrorCode *errorCode = nullptr);
QPair<QString, QString> getDnsForConfig(int serverIndex);
QString &processConfigWithDnsSettings(int serverIndex, DockerContainer container, Proto proto, QString &config);
@@ -31,8 +32,7 @@ public:
QString &processConfigWithExportSettings(int serverIndex, DockerContainer container, Proto proto, QString &config);
// workaround for containers which is not support normal configaration
void updateContainerConfigAfterInstallation(DockerContainer container,
QJsonObject &containerConfig, const QString &stdOut);
void updateContainerConfigAfterInstallation(DockerContainer container, QJsonObject &containerConfig, const QString &stdOut);
std::shared_ptr<OpenVpnConfigurator> openVpnConfigurator;
std::shared_ptr<ShadowSocksConfigurator> shadowSocksConfigurator;
@@ -40,6 +40,7 @@ public:
std::shared_ptr<WireguardConfigurator> wireguardConfigurator;
std::shared_ptr<Ikev2Configurator> ikev2Configurator;
std::shared_ptr<SshConfigurator> sshConfigurator;
std::shared_ptr<V2RayConfigurator> v2RayConfigurator;
};
#endif // VPN_CONFIGURATOR_H
+20 -23
View File
@@ -7,13 +7,11 @@
#include <QTemporaryFile>
#include <QJsonDocument>
#include <openssl/rand.h>
#include <openssl/rsa.h>
#include <openssl/x509.h>
#include <openssl/pem.h>
#include "containers/containers_defs.h"
#include "core/server_defs.h"
#include "core/scripts_registry.h"
@@ -21,10 +19,9 @@
#include "core/servercontroller.h"
#include "settings.h"
WireguardConfigurator::WireguardConfigurator(std::shared_ptr<Settings> settings, QObject *parent):
ConfiguratorBase(settings, parent)
WireguardConfigurator::WireguardConfigurator(std::shared_ptr<Settings> settings,
QObject *parent): ConfiguratorBase(settings, parent)
{
}
WireguardConfigurator::ConnectionData WireguardConfigurator::genClientKeys()
@@ -59,7 +56,9 @@ WireguardConfigurator::ConnectionData WireguardConfigurator::genClientKeys()
}
WireguardConfigurator::ConnectionData WireguardConfigurator::prepareWireguardConfig(const ServerCredentials &credentials,
DockerContainer container, const QJsonObject &containerConfig, ErrorCode *errorCode)
DockerContainer container,
const QJsonObject &containerConfig,
ErrorCode *errorCode)
{
WireguardConfigurator::ConnectionData connData = WireguardConfigurator::genClientKeys();
connData.host = credentials.hostName;
@@ -95,8 +94,7 @@ WireguardConfigurator::ConnectionData WireguardConfigurator::prepareWireguardCon
// Calc next IP address
if (ips.isEmpty()) {
nextIpNumber = "2";
}
else {
} else {
int next = ips.last().split(".").last().toInt() + 1;
if (next > 254) {
if (errorCode) *errorCode = ErrorCode::AddressPoolError;
@@ -120,14 +118,16 @@ WireguardConfigurator::ConnectionData WireguardConfigurator::prepareWireguardCon
}
// Get keys
connData.serverPubKey = serverController.getTextFileFromContainer(container, credentials, amnezia::protocols::wireguard::serverPublicKeyPath, &e);
connData.serverPubKey = serverController.getTextFileFromContainer(container, credentials,
amnezia::protocols::wireguard::serverPublicKeyPath, &e);
connData.serverPubKey.replace("\n", "");
if (e) {
if (errorCode) *errorCode = e;
return connData;
}
connData.pskKey = serverController.getTextFileFromContainer(container, credentials, amnezia::protocols::wireguard::serverPskKeyPath, &e);
connData.pskKey = serverController.getTextFileFromContainer(container, credentials,
amnezia::protocols::wireguard::serverPskKeyPath, &e);
connData.pskKey.replace("\n", "");
if (e) {
@@ -136,32 +136,29 @@ WireguardConfigurator::ConnectionData WireguardConfigurator::prepareWireguardCon
}
// Add client to config
QString configPart = QString(
"[Peer]\n"
"PublicKey = %1\n"
"PresharedKey = %2\n"
"AllowedIPs = %3/32\n\n").
arg(connData.clientPubKey).
arg(connData.pskKey).
arg(connData.clientIP);
QString configPart = QString("[Peer]\n"
"PublicKey = %1\n"
"PresharedKey = %2\n"
"AllowedIPs = %3/32\n\n").arg(connData.clientPubKey, connData.pskKey, connData.clientIP);
e = serverController.uploadTextFileToContainer(container, credentials, configPart,
protocols::wireguard::serverConfigPath, libssh::SftpOverwriteMode::SftpAppendToExisting);
protocols::wireguard::serverConfigPath,
libssh::SftpOverwriteMode::SftpAppendToExisting);
if (e) {
if (errorCode) *errorCode = e;
return connData;
}
QString script = "sudo docker exec -i $CONTAINER_NAME bash -c 'wg syncconf wg0 <(wg-quick strip /opt/amnezia/wireguard/wg0.conf)'";
e = serverController.runScript(credentials,
serverController.replaceVars("sudo docker exec -i $CONTAINER_NAME bash -c 'wg syncconf wg0 <(wg-quick strip /opt/amnezia/wireguard/wg0.conf)'",
serverController.genVarsForScript(credentials, container)));
serverController.replaceVars(script, serverController.genVarsForScript(credentials, container)));
return connData;
}
QString WireguardConfigurator::genWireguardConfig(const ServerCredentials &credentials,
DockerContainer container, const QJsonObject &containerConfig, ErrorCode *errorCode)
QString WireguardConfigurator::genWireguardConfig(const ServerCredentials &credentials, DockerContainer container,
const QJsonObject &containerConfig, ErrorCode *errorCode)
{
ServerController serverController(m_settings);
QString config = serverController.replaceVars(amnezia::scriptData(ProtocolScriptType::wireguard_template, container),
@@ -23,15 +23,14 @@ public:
};
QString genWireguardConfig(const ServerCredentials &credentials, DockerContainer container,
const QJsonObject &containerConfig, ErrorCode *errorCode = nullptr);
const QJsonObject &containerConfig, ErrorCode *errorCode = nullptr);
QString processConfigWithLocalSettings(QString config);
QString processConfigWithExportSettings(QString config);
private:
ConnectionData prepareWireguardConfig(const ServerCredentials &credentials,
DockerContainer container, const QJsonObject &containerConfig, ErrorCode *errorCode = nullptr);
ConnectionData prepareWireguardConfig(const ServerCredentials &credentials, DockerContainer container,
const QJsonObject &containerConfig, ErrorCode *errorCode = nullptr);
ConnectionData genClientKeys();
};
+8
View File
@@ -55,6 +55,9 @@ QVector<amnezia::Proto> ContainerProps::protocolsForContainer(amnezia::DockerCon
case DockerContainer::Ipsec:
return { Proto::Ikev2 /*, Protocol::L2tp */};
case DockerContainer::V2Ray:
return { Proto::OpenVpn, Proto::V2Ray };
case DockerContainer::Dns:
return { };
@@ -86,6 +89,7 @@ QMap<DockerContainer, QString> ContainerProps::containerHumanNames()
{DockerContainer::Cloak, "OpenVpn over Cloak"},
{DockerContainer::WireGuard, "WireGuard"},
{DockerContainer::Ipsec, QObject::tr("IPsec")},
{DockerContainer::V2Ray, "V2Ray"},
{DockerContainer::TorWebSite, QObject::tr("Web site in Tor network")},
{DockerContainer::Dns, QObject::tr("DNS Service")},
@@ -103,6 +107,7 @@ QMap<DockerContainer, QString> ContainerProps::containerDescriptions()
"configured with traffic masking by Cloak plugin")},
{DockerContainer::WireGuard, QObject::tr("WireGuard container")},
{DockerContainer::Ipsec, QObject::tr("IPsec container")},
{DockerContainer::V2Ray, QObject::tr("V2Ray container")},
{DockerContainer::TorWebSite, QObject::tr("Web site in Tor network")},
{DockerContainer::Dns, QObject::tr("DNS Service")},
@@ -120,6 +125,8 @@ amnezia::ServiceType ContainerProps::containerService(DockerContainer c)
case DockerContainer::ShadowSocks : return ServiceType::Vpn;
case DockerContainer::WireGuard : return ServiceType::Vpn;
case DockerContainer::Ipsec : return ServiceType::Vpn;
case DockerContainer::V2Ray : return ServiceType::Vpn;
case DockerContainer::TorWebSite : return ServiceType::Other;
case DockerContainer::Dns : return ServiceType::Other;
//case DockerContainer::FileShare : return ServiceType::Other;
@@ -137,6 +144,7 @@ Proto ContainerProps::defaultProtocol(DockerContainer c)
case DockerContainer::ShadowSocks : return Proto::ShadowSocks;
case DockerContainer::WireGuard : return Proto::WireGuard;
case DockerContainer::Ipsec : return Proto::Ikev2;
case DockerContainer::V2Ray : return Proto::V2Ray;
case DockerContainer::TorWebSite : return Proto::TorWebSite;
case DockerContainer::Dns : return Proto::Dns;
+1
View File
@@ -19,6 +19,7 @@ enum DockerContainer {
Cloak,
WireGuard,
Ipsec,
V2Ray,
//non-vpn
TorWebSite,
+4 -1
View File
@@ -55,6 +55,7 @@ enum ErrorCode
ShadowSocksExecutableMissing,
CloakExecutableMissing,
AmneziaServiceConnectionFailed,
V2RayExecutableMissing,
ExecutableMissing,
// VPN errors
@@ -67,7 +68,9 @@ enum ErrorCode
OpenSslFailed,
OpenVpnExecutableCrashed,
ShadowSocksExecutableCrashed,
CloakExecutableCrashed
CloakExecutableCrashed,
V2RayExecutableCrashed,
V2RayKeyMissing
};
} // namespace amnezia
+4
View File
@@ -51,6 +51,10 @@ QString errorString(ErrorCode code){
case (AmneziaServiceConnectionFailed): return QObject::tr("Amnezia helper service error");
case (OpenSslFailed): return QObject::tr("OpenSSL failed");
// V2Ray errors
case (V2RayExecutableMissing): return QObject::tr("V2Ray (v2ray) executable missing");
case (V2RayKeyMissing): return QObject::tr("V2Ray key missing");
// VPN errors
case (OpenVpnAdaptersInUseError): return QObject::tr("Can't connect: another VPN connection is active");
case (OpenVpnTapAdapterError): return QObject::tr("Can't setup OpenVPN TAP network adapter");
+3
View File
@@ -12,6 +12,7 @@ QString amnezia::scriptFolder(amnezia::DockerContainer container)
case DockerContainer::ShadowSocks: return QLatin1String("openvpn_shadowsocks");
case DockerContainer::WireGuard: return QLatin1String("wireguard");
case DockerContainer::Ipsec: return QLatin1String("ipsec");
case DockerContainer::V2Ray: return QLatin1String("openvpn_v2ray_vmess");
case DockerContainer::TorWebSite: return QLatin1String("website_tor");
case DockerContainer::Dns: return QLatin1String("dns");
@@ -44,6 +45,8 @@ QString amnezia::scriptName(ProtocolScriptType type)
case ProtocolScriptType::container_startup: return QLatin1String("start.sh");
case ProtocolScriptType::openvpn_template: return QLatin1String("template.ovpn");
case ProtocolScriptType::wireguard_template: return QLatin1String("template.conf");
case ProtocolScriptType::v2ray_client_template: return QLatin1String("template_v2ray_client.json");
case ProtocolScriptType::shadowsocks_client_template: return QLatin1String("template_ss_client.json");
}
}
+3 -1
View File
@@ -25,7 +25,9 @@ enum ProtocolScriptType {
configure_container,
container_startup,
openvpn_template,
wireguard_template
wireguard_template,
v2ray_client_template,
shadowsocks_client_template
};
+5
View File
@@ -516,6 +516,7 @@ ServerController::Vars ServerController::genVarsForScript(const ServerCredential
const QJsonObject &ssConfig = config.value(ProtocolProps::protoToString(Proto::ShadowSocks)).toObject();
const QJsonObject &wireguarConfig = config.value(ProtocolProps::protoToString(Proto::WireGuard)).toObject();
const QJsonObject &sftpConfig = config.value(ProtocolProps::protoToString(Proto::Sftp)).toObject();
const QJsonObject &v2RayConfig = config.value(ProtocolProps::protoToString(Proto::V2Ray)).toObject();
//
Vars vars;
@@ -567,6 +568,10 @@ ServerController::Vars ServerController::genVarsForScript(const ServerCredential
vars.append({{"$WIREGUARD_SERVER_PORT", wireguarConfig.value(config_key::port).toString(protocols::wireguard::defaultPort) }});
// V2Ray vars
vars.append({{"$V2RAY_VMESS_PORT", v2RayConfig.value(config_key::port).toString(protocols::v2ray::defaultServerPort) }});
vars.append({{"$V2RAY_SOCKS_LOCAL_PORT", v2RayConfig.value(config_key::local_port).toString(protocols::v2ray::defaultLocalPort) }});
// IPsec vars
vars.append({{"$IPSEC_VPN_L2TP_NET", "192.168.42.0/24"}});
vars.append({{"$IPSEC_VPN_L2TP_POOL", "192.168.42.10-192.168.42.250"}});
@@ -52,26 +52,25 @@ ErrorCode OpenVpnOverCloakProtocol::start()
args << "-u";
}
qDebug().noquote() << "OpenVpnOverCloakProtocol::start()"
<< cloakExecPath() << args.join(" ");
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](){
connect(&m_ckProcess, &QProcess::readyReadStandardOutput, this, [this]() {
qDebug().noquote() << "ck-client:" << m_ckProcess.readAllStandardOutput();
});
m_errorHandlerConnection = connect(&m_ckProcess, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished), this, [this](int exitCode, QProcess::ExitStatus exitStatus){
m_errorHandlerConnection = 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::Disconnected);
if (exitStatus != QProcess::NormalExit){
if (exitStatus != QProcess::NormalExit) {
emit protocolError(amnezia::ErrorCode::CloakExecutableCrashed);
stop();
}
if (exitCode !=0 ){
if (exitCode !=0 ) {
emit protocolError(amnezia::ErrorCode::InternalError);
stop();
}
@@ -84,8 +83,9 @@ ErrorCode OpenVpnOverCloakProtocol::start()
setConnectionState(VpnConnectionState::Connecting);
return OpenVpnProtocol::start();
} else {
return ErrorCode::CloakExecutableMissing;
}
else return ErrorCode::CloakExecutableMissing;
#endif
}
+12 -5
View File
@@ -75,6 +75,7 @@ QMap<amnezia::Proto, QString> ProtocolProps::protocolHumanNames()
{Proto::WireGuard, "WireGuard"},
{Proto::Ikev2, "IKEv2"},
{Proto::L2tp, "L2TP"},
{Proto::V2Ray, "V2Ray"},
{Proto::TorWebSite, "Web site in Tor network"},
{Proto::Dns, "DNS Service"},
@@ -96,10 +97,12 @@ amnezia::ServiceType ProtocolProps::protocolService(Proto p)
case Proto::Cloak : return ServiceType::Vpn;
case Proto::ShadowSocks : return ServiceType::Vpn;
case Proto::WireGuard : return ServiceType::Vpn;
case Proto::TorWebSite : return ServiceType::Other;
case Proto::V2Ray : return ServiceType::Vpn;
case Proto::TorWebSite : return ServiceType::Other;
case Proto::Dns : return ServiceType::Other;
case Proto::FileShare : return ServiceType::Other;
default: return ServiceType::Other;
default: return ServiceType::Other;
}
}
@@ -113,12 +116,13 @@ int ProtocolProps::defaultPort(Proto p)
case Proto::WireGuard : return 51820;
case Proto::Ikev2 : return -1;
case Proto::L2tp : return -1;
case Proto::V2Ray : return 10086;
case Proto::TorWebSite : return -1;
case Proto::Dns : return 53;
case Proto::FileShare : return 139;
case Proto::Sftp : return 222;
default: return -1;
default: return -1;
}
}
@@ -132,12 +136,13 @@ bool ProtocolProps::defaultPortChangeable(Proto p)
case Proto::WireGuard : return true;
case Proto::Ikev2 : return false;
case Proto::L2tp : return false;
case Proto::V2Ray : return true;
case Proto::TorWebSite : return true;
case Proto::Dns : return false;
case Proto::FileShare : return false;
default: return -1;
default: return -1;
}
}
@@ -151,6 +156,7 @@ TransportProto ProtocolProps::defaultTransportProto(Proto p)
case Proto::WireGuard : return TransportProto::Udp;
case Proto::Ikev2 : return TransportProto::Udp;
case Proto::L2tp : return TransportProto::Udp;
case Proto::V2Ray : return TransportProto::Tcp;
// non-vpn
case Proto::TorWebSite : return TransportProto::Tcp;
case Proto::Dns : return TransportProto::Udp;
@@ -169,12 +175,13 @@ bool ProtocolProps::defaultTransportProtoChangeable(Proto p)
case Proto::WireGuard : return false;
case Proto::Ikev2 : return false;
case Proto::L2tp : return false;
case Proto::V2Ray : return false;
// non-vpn
case Proto::TorWebSite : return false;
case Proto::Dns : return false;
case Proto::FileShare : return false;
case Proto::Sftp : return false;
default: return false;
default: return false;
}
}
+7
View File
@@ -124,6 +124,12 @@ constexpr char serverPskKeyPath[] = "/opt/amnezia/wireguard/wireguard_psk.key";
}
namespace v2ray {
constexpr char v2rayKeyPath[] = "/opt/amnezia/v2ray/v2ray.key";
constexpr char defaultLocalPort[] = "1080";
constexpr char defaultServerPort[] = "10086";
}
namespace sftp {
constexpr char defaultUserName[] = "sftp_user";
@@ -148,6 +154,7 @@ enum Proto {
WireGuard,
Ikev2,
L2tp,
V2Ray,
// non-vpn
TorWebSite,
+10 -24
View File
@@ -9,7 +9,7 @@
#include <QJsonObject>
ShadowSocksVpnProtocol::ShadowSocksVpnProtocol(const QJsonObject &configuration, QObject *parent):
OpenVpnProtocol(configuration, parent)
OpenVpnProtocol(configuration, parent)
{
readShadowSocksConfiguration(configuration);
}
@@ -32,7 +32,6 @@ ErrorCode ShadowSocksVpnProtocol::start()
return lastError();
}
#ifndef Q_OS_IOS
if (Utils::processIsRunning(Utils::executable("ss-local", false))) {
Utils::killProcessByName(Utils::executable("ss-local", false));
@@ -48,30 +47,28 @@ ErrorCode ShadowSocksVpnProtocol::start()
#ifdef Q_OS_LINUX
QStringList args = QStringList() << "-c" << m_shadowSocksCfgFile.fileName();
#else
QStringList args = QStringList() << "-c" << m_shadowSocksCfgFile.fileName()
<< "--no-delay";
QStringList args = QStringList() << "-c" << m_shadowSocksCfgFile.fileName() << "--no-delay";
#endif
qDebug().noquote() << "ShadowSocksVpnProtocol::start()"
<< shadowSocksExecPath() << args.join(" ");
qDebug().noquote() << "ShadowSocksVpnProtocol::start()" << shadowSocksExecPath() << args.join(" ");
m_ssProcess.setProcessChannelMode(QProcess::MergedChannels);
m_ssProcess.setProgram(shadowSocksExecPath());
m_ssProcess.setArguments(args);
connect(&m_ssProcess, &QProcess::readyReadStandardOutput, this, [this](){
connect(&m_ssProcess, &QProcess::readyReadStandardOutput, this, [this]() {
qDebug().noquote() << "ss-local:" << m_ssProcess.readAllStandardOutput();
});
connect(&m_ssProcess, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished), this, [this](int exitCode, QProcess::ExitStatus exitStatus){
connect(&m_ssProcess, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished), this, [this](int exitCode, QProcess::ExitStatus exitStatus) {
qDebug().noquote() << "ShadowSocksVpnProtocol finished, exitCode, exiStatus" << exitCode << exitStatus;
setConnectionState(VpnProtocol::Disconnected);
if (exitStatus != QProcess::NormalExit){
if (exitStatus != QProcess::NormalExit) {
emit protocolError(amnezia::ErrorCode::ShadowSocksExecutableCrashed);
stop();
}
if (exitCode !=0 ){
if (exitCode !=0 ) {
emit protocolError(amnezia::ErrorCode::InternalError);
stop();
}
@@ -84,8 +81,9 @@ ErrorCode ShadowSocksVpnProtocol::start()
setConnectionState(VpnConnectionState::Connecting);
return OpenVpnProtocol::start();
} else {
return ErrorCode::ShadowSocksExecutableMissing;
}
else return ErrorCode::ShadowSocksExecutableMissing;
#else
return ErrorCode::NotImplementedError;
#endif
@@ -116,17 +114,5 @@ QString ShadowSocksVpnProtocol::shadowSocksExecPath()
void ShadowSocksVpnProtocol::readShadowSocksConfiguration(const QJsonObject &configuration)
{
QJsonObject shadowSocksConfig = configuration.value(ProtocolProps::key_proto_config_data(Proto::ShadowSocks)).toObject();
bool isLocalPortConvertOk = false;
bool isServerPortConvertOk = false;
int localPort = shadowSocksConfig.value("local_port").toString().toInt(&isLocalPortConvertOk);
int serverPort = shadowSocksConfig.value("server_port").toString().toInt(&isServerPortConvertOk);
if (!isLocalPortConvertOk) {
qDebug() << "Error when converting local_port field in ShadowSocks config";
} else if (!isServerPortConvertOk) {
qDebug() << "Error when converting server_port field in ShadowSocks config";
}
shadowSocksConfig["local_port"] = localPort;
shadowSocksConfig["server_port"] = serverPort;
m_shadowSocksConfig = shadowSocksConfig;
m_shadowSocksConfig = configuration.value(ProtocolProps::key_proto_config_data(Proto::ShadowSocks)).toObject();
}
+5 -7
View File
@@ -1,9 +1,9 @@
#ifndef SHADOWSOCKSVPNPROTOCOL_H
#define SHADOWSOCKSVPNPROTOCOL_H
#include "openvpnprotocol.h"
#include "QProcess"
#include "containers/containers_defs.h"
#include "openvpnprotocol.h"
class ShadowSocksVpnProtocol : public OpenVpnProtocol
{
@@ -14,20 +14,18 @@ public:
ErrorCode start() override;
void stop() override;
protected:
void readShadowSocksConfiguration(const QJsonObject &configuration);
protected:
QJsonObject m_shadowSocksConfig;
private:
static QString shadowSocksExecPath();
void readShadowSocksConfiguration(const QJsonObject &configuration);
private:
#ifndef Q_OS_IOS
QProcess m_ssProcess;
#endif
QTemporaryFile m_shadowSocksCfgFile;
static QString shadowSocksExecPath();
};
#endif // SHADOWSOCKSVPNPROTOCOL_H
+108
View File
@@ -0,0 +1,108 @@
#include "v2rayprotocol.h"
#include <QThread>
#include <QFileInfo>
#include <QJsonDocument>
#include "utilities.h"
V2RayProtocol::V2RayProtocol(const QJsonObject &configuration, QObject *parent) : OpenVpnProtocol(configuration, parent)
{
writeV2RayConfiguration(configuration);
}
V2RayProtocol::~V2RayProtocol()
{
qDebug() << "V2RayProtocol::~V2RayProtocol";
V2RayProtocol::stop();
QThread::msleep(200);
}
ErrorCode V2RayProtocol::start()
{
#ifndef Q_OS_IOS
if (!QFileInfo::exists(v2RayExecPath())) {
setLastError(ErrorCode::V2RayExecutableMissing);
return lastError();
}
if (Utils::processIsRunning(Utils::executable("v2ray", false))) {
Utils::killProcessByName(Utils::executable("v2ray", false));
}
QStringList args = QStringList() << "-c" << m_v2RayConfigFile.fileName();
qDebug().noquote() << "V2RayProtocol::start()" << v2RayExecPath() << args.join(" ");
m_v2RayProcess.setProcessChannelMode(QProcess::MergedChannels);
m_v2RayProcess.setProgram(v2RayExecPath());
m_v2RayProcess.setArguments(args);
connect(&m_v2RayProcess, &QProcess::readyReadStandardOutput, this, [this]() {
qDebug().noquote() << "V2Ray:" << m_v2RayProcess.readAllStandardOutput();
});
connect(&m_v2RayProcess, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished), this, [this](int exitCode, QProcess::ExitStatus exitStatus) {
qDebug().noquote() << "V2RayProtocol finished, exitCode, exiStatus" << exitCode << exitStatus;
setConnectionState(VpnProtocol::Disconnected);
if (exitStatus != QProcess::NormalExit) {
emit protocolError(amnezia::ErrorCode::V2RayExecutableCrashed);
stop();
}
if (exitCode != 0 ) {
emit protocolError(amnezia::ErrorCode::InternalError);
stop();
}
});
m_v2RayProcess.start();
m_v2RayProcess.waitForStarted();
if (m_v2RayProcess.state() == QProcess::ProcessState::Running) {
setConnectionState(VpnConnectionState::Connecting);
return OpenVpnProtocol::start();
} else {
return ErrorCode::V2RayExecutableMissing;
}
#else
return ErrorCode::NotImplementedError;
#endif
return ErrorCode::NoError;
}
void V2RayProtocol::stop()
{
OpenVpnProtocol::stop();
qDebug() << "V2RayProtocol::stop()";
#ifndef Q_OS_IOS
m_v2RayProcess.terminate();
#endif
#ifdef Q_OS_WIN
Utils::signalCtrl(m_v2RayProcess.processId(), CTRL_C_EVENT);
#endif
}
void V2RayProtocol::writeV2RayConfiguration(const QJsonObject &configuration)
{
m_v2RayConfig = configuration.value(ProtocolProps::key_proto_config_data(Proto::V2Ray)).toObject();
#ifdef QT_DEBUG
m_v2RayConfigFile.setAutoRemove(false);
#endif
m_v2RayConfigFile.open();
m_v2RayConfigFile.write(QJsonDocument(m_v2RayConfig).toJson());
m_v2RayConfigFile.close();
}
const QString V2RayProtocol::v2RayExecPath() const
{
#ifdef Q_OS_WIN
return Utils::executable(QString("v2ray/v2ray"), true);
#else
return Utils::executable(QString("v2ray"), true);
#endif
}
+30
View File
@@ -0,0 +1,30 @@
#ifndef V2RAYPROTOCOL_H
#define V2RAYPROTOCOL_H
#include "QProcess"
#include "QTemporaryFile"
#include "openvpnprotocol.h"
class V2RayProtocol : public OpenVpnProtocol
{
public:
V2RayProtocol(const QJsonObject& configuration, QObject* parent = nullptr);
virtual ~V2RayProtocol() override;
ErrorCode start() override;
void stop() override;
private:
QJsonObject m_v2RayConfig;
QTemporaryFile m_v2RayConfigFile;
#ifndef Q_OS_IOS
QProcess m_v2RayProcess;
#endif
void writeV2RayConfiguration(const QJsonObject &configuration);
const QString v2RayExecPath() const;
};
#endif // V2RAYPROTOCOL_H
+2
View File
@@ -9,6 +9,7 @@
#include "shadowsocksvpnprotocol.h"
#include "openvpnovercloakprotocol.h"
#include "wireguardprotocol.h"
#include "v2rayprotocol.h"
#endif
#ifdef Q_OS_WINDOWS
@@ -114,6 +115,7 @@ VpnProtocol *VpnProtocol::factory(DockerContainer container, const QJsonObject&
case DockerContainer::Cloak: return new OpenVpnOverCloakProtocol(configuration);
case DockerContainer::ShadowSocks: return new ShadowSocksVpnProtocol(configuration);
case DockerContainer::WireGuard: return new WireguardProtocol(configuration);
case DockerContainer::V2Ray: return new V2RayProtocol(configuration);
#endif
default: return nullptr;
}
+8
View File
@@ -166,5 +166,13 @@
<file>ui/qml/Pages/PageAdvancedServerSettings.qml</file>
<file>ui/qml/Controls/PopupWarning.qml</file>
<file>ui/qml/Controls/PopupWithTextField.qml</file>
<file>ui/qml/Pages/Protocols/PageProtoV2Ray.qml</file>
<file>server_scripts/openvpn_v2ray_vmess/configure_container.sh</file>
<file>server_scripts/openvpn_v2ray_vmess/Dockerfile</file>
<file>server_scripts/openvpn_v2ray_vmess/run_container.sh</file>
<file>server_scripts/openvpn_v2ray_vmess/start.sh</file>
<file>server_scripts/openvpn_v2ray_vmess/template.ovpn</file>
<file>server_scripts/openvpn_v2ray_vmess/template_v2ray_client.json</file>
<file>server_scripts/openvpn_shadowsocks/template_ss_client.json</file>
</qresource>
</RCC>
+1 -1
View File
@@ -1 +1 @@
sudo docker build -t $CONTAINER_NAME $DOCKERFILE_FOLDER --build-arg SERVER_ARCH=$(uname -m)
sudo docker build --network host -t $CONTAINER_NAME $DOCKERFILE_FOLDER --build-arg SERVER_ARCH=$(uname -m)
@@ -0,0 +1,8 @@
{
"local_port": $SHADOWSOCKS_LOCAL_PORT,
"method": "$SHADOWSOCKS_CIPHER",
"password": "$SHADOWSOCKS_PASSWORD",
"server": "$REMOTE_HOST",
"server_port": $SHADOWSOCKS_SERVER_PORT,
"timeout": 60
}
@@ -0,0 +1,51 @@
FROM alpine:3.15
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 apk add --no-cache v2ray
# 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 [ "" ]
@@ -0,0 +1,70 @@
cat > /opt/amnezia/openvpn/server.conf <<EOF
port $OPENVPN_PORT
proto $OPENVPN_TRANSPORT_PROTO
dev tun
ca /opt/amnezia/openvpn/ca.crt
cert /opt/amnezia/openvpn/AmneziaReq.crt
key /opt/amnezia/openvpn/AmneziaReq.key
dh /opt/amnezia/openvpn/dh.pem
server $OPENVPN_SUBNET_IP $OPENVPN_SUBNET_MASK
ifconfig-pool-persist ipp.txt
duplicate-cn
keepalive 10 120
$OPENVPN_NCP_DISABLE
cipher $OPENVPN_CIPHER
data-ciphers $OPENVPN_CIPHER
auth $OPENVPN_HASH
user nobody
group nobody
persist-key
persist-tun
status openvpn-status.log
verb 1
tls-server
tls-version-min 1.2
$OPENVPN_TLS_AUTH
$OPENVPN_ADDITIONAL_SERVER_CONFIG
EOF
# V2RAY_VMESS_PORT port for v2ray listening, for example 10086.
# V2RAY_VMESS_CLIENT_UUID client's id and secret as UUID.
# UUID is 32 hexadecimal digits /([0-9a-f]-?){32}/ (128 bit value).
mkdir -p /opt/amnezia/v2ray
cd /opt/amnezia/v2ray
V2RAY_VMESS_CLIENT_UUID=$(cat /proc/sys/kernel/random/uuid)
echo $V2RAY_VMESS_CLIENT_UUID > /opt/amnezia/v2ray/v2ray.key
cat > /opt/amnezia/v2ray/v2ray-server.json <<EOF
{
"log": {
"loglevel": "None"
},
"inbounds": [
{
"port": $V2RAY_VMESS_PORT,
"protocol": "vmess",
"settings": {
"clients": [
{
"id": "$V2RAY_VMESS_CLIENT_UUID",
"level": 1,
"alterId": 64
}
]
}
}
],
"outbounds": [
{
"protocol": "freedom",
"settings": {}
}
],
"policy": {
"levels": {
"0": {"uplinkOnly": 0}
}
}
}
EOF
@@ -0,0 +1,24 @@
# Run container
sudo docker run -d \
--log-driver none \
--restart always \
--cap-add=NET_ADMIN \
-p $V2RAY_VMESS_PORT:$V2RAY_VMESS_PORT/tcp \
--name $CONTAINER_NAME $CONTAINER_NAME
sudo docker network connect amnezia-dns-net $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'
@@ -0,0 +1,31 @@
#!/bin/bash
# This scripts copied from Amnezia client to Docker container to /opt/amnezia and launched every time container starts
echo "Container startup"
ifconfig eth0:0 $SERVER_IP_ADDRESS netmask 255.255.255.255 up
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 $OPENVPN_SUBNET_IP/$OPENVPN_SUBNET_CIDR -j ACCEPT
iptables -A FORWARD -i tun0 -o eth1 -s $OPENVPN_SUBNET_IP/$OPENVPN_SUBNET_CIDR -j ACCEPT
iptables -A FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -t nat -A POSTROUTING -s $OPENVPN_SUBNET_IP/$OPENVPN_SUBNET_CIDR -o eth0 -j MASQUERADE
iptables -t nat -A POSTROUTING -s $OPENVPN_SUBNET_IP/$OPENVPN_SUBNET_CIDR -o eth1 -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
if [ -f /opt/amnezia/v2ray/v2ray-server.json ]; then (v2ray -config /opt/amnezia/v2ray/v2ray-server.json &); fi
tail -f /dev/null
@@ -0,0 +1,39 @@
client
dev tun
proto $OPENVPN_TRANSPORT_PROTO
resolv-retry infinite
nobind
persist-key
persist-tun
$OPENVPN_NCP_DISABLE
cipher $OPENVPN_CIPHER
auth $OPENVPN_HASH
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
socks-proxy 127.0.0.1 $V2RAY_SOCKS_LOCAL_PORT
route $REMOTE_HOST 255.255.255.255 net_gateway
remote 127.0.0.1 $OPENVPN_PORT
$OPENVPN_ADDITIONAL_CLIENT_CONFIG
<ca>
$OPENVPN_CA_CERT
</ca>
<cert>
$OPENVPN_CLIENT_CERT
</cert>
<key>
$OPENVPN_PRIV_KEY
</key>
<tls-auth>
$OPENVPN_TA_KEY
</tls-auth>
@@ -0,0 +1,31 @@
{
"inbounds": [
{
"listen": "127.0.0.1",
"port": $V2RAY_SOCKS_LOCAL_PORT,
"protocol": "socks",
"settings": {
"auth": "noauth",
"udp": true
}
}
],
"outbounds": [
{
"protocol": "vmess",
"settings": {
"vnext": [
{
"address": "$REMOTE_HOST",
"port": $V2RAY_VMESS_PORT,
"users": [
{
"id": "$V2RAY_VMESS_CLIENT_UUID"
}
]
}
]
}
}
]
}
@@ -55,6 +55,7 @@ public:
friend class ShadowSocksLogic;
friend class CloakLogic;
friend class UiLogic;
friend class V2RayLogic;
void onUpdatePage() override;
ErrorCode doInstallAction(const std::function<ErrorCode()> &action);
@@ -166,7 +166,7 @@ void OpenVpnLogic::onPushButtonSaveClicked()
auto installAction = [this, containerConfig, &newContainerConfig]() {
ServerController serverController(m_settings);
return serverController.updateContainer(m_settings->serverCredentials(uiLogic()->m_selectedServerIndex),
uiLogic()->m_selectedDockerContainer, containerConfig, newContainerConfig);
uiLogic()->m_selectedDockerContainer, containerConfig, newContainerConfig);
};
ErrorCode e = uiLogic()->pageLogic<ServerConfiguringProgressLogic>()->doInstallAction(installAction, pageFunc, progressBarFunc,
@@ -50,6 +50,7 @@ QJsonObject ShadowSocksLogic::getProtocolConfigFromPage(QJsonObject oldConfig)
void ShadowSocksLogic::onPushButtonSaveClicked()
{
QJsonObject protocolConfig = m_settings->protocolConfig(uiLogic()->m_selectedServerIndex, uiLogic()->m_selectedDockerContainer, Proto::ShadowSocks);
protocolConfig = getProtocolConfigFromPage(protocolConfig);
QJsonObject containerConfig = m_settings->containerConfig(uiLogic()->m_selectedServerIndex, uiLogic()->m_selectedDockerContainer);
QJsonObject newContainerConfig = containerConfig;
@@ -108,7 +109,7 @@ void ShadowSocksLogic::onPushButtonSaveClicked()
auto installAction = [this, containerConfig, &newContainerConfig]() {
ServerController serverController(m_settings);
return serverController.updateContainer(m_settings->serverCredentials(uiLogic()->m_selectedServerIndex),
uiLogic()->m_selectedDockerContainer, containerConfig, newContainerConfig);
uiLogic()->m_selectedDockerContainer, containerConfig, newContainerConfig);
};
ErrorCode e = uiLogic()->pageLogic<ServerConfiguringProgressLogic>()->doInstallAction(installAction, pageFunc, progressBarFunc,
saveButtonFunc, waitInfoFunc,
@@ -0,0 +1,128 @@
#include "V2RayLogic.h"
#include <functional>
#include "core/servercontroller.h"
#include "ui/pages_logic/ServerConfiguringProgressLogic.h"
#include "ui/uilogic.h"
using namespace amnezia;
using namespace PageEnumNS;
V2RayLogic::V2RayLogic(UiLogic *logic, QObject *parent):
PageProtocolLogicBase(logic, parent),
m_lineEditServerPortText{},
m_pushButtonSaveVisible{false},
m_progressBarResetVisible{false},
m_lineEditServerPortEnabled{false},
m_labelInfoVisible{true},
m_labelInfoText{},
m_progressBarResetValue{0},
m_progressBarResetMaximium{100},
m_lineEditLocalPortEnabled{false},
m_lineEditLocalPortText{}
{
}
void V2RayLogic::updateProtocolPage(const QJsonObject &v2RayConfig, DockerContainer container, bool haveAuthData)
{
set_pageEnabled(haveAuthData);
set_pushButtonSaveVisible(haveAuthData);
set_progressBarResetVisible(haveAuthData);
set_lineEditServerPortText(v2RayConfig.value(config_key::port).toString(protocols::v2ray::defaultServerPort));
set_lineEditServerPortEnabled(container == DockerContainer::V2Ray);
set_lineEditLocalPortText(v2RayConfig.value(config_key::local_port).toString(protocols::v2ray::defaultLocalPort));
set_lineEditLocalPortEnabled(container == DockerContainer::V2Ray);
}
QJsonObject V2RayLogic::getProtocolConfigFromPage(QJsonObject oldConfig)
{
oldConfig.insert(config_key::port, lineEditServerPortText());
oldConfig.insert(config_key::local_port, lineEditLocalPortText());
return oldConfig;
}
void V2RayLogic::onPushButtonSaveClicked()
{
QJsonObject protocolConfig = m_settings->protocolConfig(uiLogic()->m_selectedServerIndex, uiLogic()->m_selectedDockerContainer, Proto::V2Ray);
protocolConfig = getProtocolConfigFromPage(protocolConfig);
QJsonObject containerConfig = m_settings->containerConfig(uiLogic()->m_selectedServerIndex, uiLogic()->m_selectedDockerContainer);
QJsonObject newContainerConfig = containerConfig;
newContainerConfig.insert(ProtocolProps::protoToString(Proto::V2Ray), protocolConfig);
ServerConfiguringProgressLogic::PageFunc pageFunc;
pageFunc.setEnabledFunc = [this] (bool enabled) -> void {
set_pageEnabled(enabled);
};
ServerConfiguringProgressLogic::ButtonFunc saveButtonFunc;
saveButtonFunc.setVisibleFunc = [this] (bool visible) -> void {
set_pushButtonSaveVisible(visible);
};
ServerConfiguringProgressLogic::LabelFunc waitInfoFunc;
waitInfoFunc.setVisibleFunc = [this] (bool visible) -> void {
set_labelInfoVisible(visible);
};
waitInfoFunc.setTextFunc = [this] (const QString& text) -> void {
set_labelInfoText(text);
};
ServerConfiguringProgressLogic::ProgressFunc progressBarFunc;
progressBarFunc.setVisibleFunc = [this] (bool visible) -> void {
set_progressBarResetVisible(visible);
};
progressBarFunc.setValueFunc = [this] (int value) -> void {
set_progressBarResetValue(value);
};
progressBarFunc.getValueFunc = [this] (void) -> int {
return progressBarResetValue();
};
progressBarFunc.getMaximiumFunc = [this] (void) -> int {
return progressBarResetMaximium();
};
progressBarFunc.setTextVisibleFunc = [this] (bool visible) -> void {
set_progressBarTextVisible(visible);
};
progressBarFunc.setTextFunc = [this] (const QString& text) -> void {
set_progressBarText(text);
};
ServerConfiguringProgressLogic::LabelFunc busyInfoFuncy;
busyInfoFuncy.setTextFunc = [this] (const QString& text) -> void {
set_labelServerBusyText(text);
};
busyInfoFuncy.setVisibleFunc = [this] (bool visible) -> void {
set_labelServerBusyVisible(visible);
};
ServerConfiguringProgressLogic::ButtonFunc cancelButtonFunc;
cancelButtonFunc.setVisibleFunc = [this] (bool visible) -> void {
set_pushButtonCancelVisible(visible);
};
progressBarFunc.setTextVisibleFunc(true);
progressBarFunc.setTextFunc(QString("Configuring..."));
auto installAction = [this, containerConfig, &newContainerConfig]() {
ServerController serverController(m_settings);
return serverController.updateContainer(m_settings->serverCredentials(uiLogic()->m_selectedServerIndex),
uiLogic()->m_selectedDockerContainer, containerConfig, newContainerConfig);
};
ErrorCode e = uiLogic()->pageLogic<ServerConfiguringProgressLogic>()->doInstallAction(installAction, pageFunc, progressBarFunc,
saveButtonFunc, waitInfoFunc,
busyInfoFuncy, cancelButtonFunc);
if (!e) {
m_settings->setContainerConfig(uiLogic()->m_selectedServerIndex, uiLogic()->m_selectedDockerContainer, newContainerConfig);
m_settings->clearLastConnectionConfig(uiLogic()->m_selectedServerIndex, uiLogic()->m_selectedDockerContainer);
}
qDebug() << "Protocol saved with code:" << e << "for" << uiLogic()->m_selectedServerIndex << uiLogic()->m_selectedDockerContainer;
}
void V2RayLogic::onPushButtonCancelClicked()
{
emit uiLogic()->pageLogic<ServerConfiguringProgressLogic>()->cancelDoInstallAction(true);
}
@@ -0,0 +1,50 @@
#ifndef V2RAYLOGIC_H
#define V2RAYLOGIC_H
#include "PageProtocolLogicBase.h"
class UiLogic;
class V2RayLogic : public PageProtocolLogicBase
{
Q_OBJECT
AUTO_PROPERTY(bool, lineEditServerPortEnabled)
AUTO_PROPERTY(QString, lineEditServerPortText)
AUTO_PROPERTY(bool, lineEditLocalPortEnabled)
AUTO_PROPERTY(QString, lineEditLocalPortText)
AUTO_PROPERTY(bool, labelInfoVisible)
AUTO_PROPERTY(QString, labelInfoText)
AUTO_PROPERTY(int, progressBarResetValue)
AUTO_PROPERTY(int, progressBarResetMaximium)
AUTO_PROPERTY(bool, progressBarResetVisible)
AUTO_PROPERTY(bool, progressBarTextVisible)
AUTO_PROPERTY(QString, progressBarText)
AUTO_PROPERTY(bool, labelServerBusyVisible)
AUTO_PROPERTY(QString, labelServerBusyText)
AUTO_PROPERTY(bool, pushButtonSaveVisible)
AUTO_PROPERTY(bool, pushButtonCancelVisible)
public:
Q_INVOKABLE void onPushButtonSaveClicked();
Q_INVOKABLE void onPushButtonCancelClicked();
public:
explicit V2RayLogic(UiLogic *uiLogic, QObject *parent = nullptr);
~V2RayLogic() = default;
void updateProtocolPage(const QJsonObject &v2rayConfig, DockerContainer container, bool haveAuthData) override;
QJsonObject getProtocolConfigFromPage(QJsonObject oldConfig) override;
private:
UiLogic *m_uiLogic;
};
#endif // V2RAYLOGIC_H
@@ -0,0 +1,158 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import ProtocolEnum 1.0
import "../"
import "../../Controls"
import "../../Config"
PageProtocolBase {
id: root
protocol: ProtocolEnum.V2Ray
logic: UiLogic.protocolLogic(protocol)
BackButton {
id: back
enabled: !logic.pushButtonCancelVisible
}
Caption {
id: caption
text: qsTr("V2Ray Settings")
}
ColumnLayout {
id: content
enabled: logic.pageEnabled
anchors.top: caption.bottom
anchors.left: root.left
anchors.right: root.right
anchors.bottom: pb_save.top
anchors.margins: 20
anchors.topMargin: 10
RowLayout {
Layout.fillWidth: true
LabelType {
Layout.preferredWidth: 0.3 * root.width - 10
height: 31
text: qsTr("Port")
}
TextFieldType {
Layout.fillWidth: true
height: 31
text: logic.lineEditServerPortText
onEditingFinished: {
logic.lineEditServerPortText = text
}
enabled: logic.lineEditServerPortEnabled
}
}
RowLayout {
Layout.fillWidth: true
LabelType {
Layout.preferredWidth: 0.3 * root.width - 10
height: 31
text: qsTr("Local port")
}
TextFieldType {
Layout.fillWidth: true
height: 31
text: logic.lineEditLocalPortText
onEditingFinished: {
logic.lineEditLocalPortText = text
}
enabled: logic.lineEditLocalPortEnabled
}
}
Item {
Layout.fillHeight: true
}
LabelType {
horizontalAlignment: Text.AlignHCenter
Layout.maximumWidth: parent.width
Layout.fillWidth: true
visible: logic.labelServerBusyVisible
text: logic.labelServerBusyText
}
LabelType {
horizontalAlignment: Text.AlignHCenter
Layout.maximumWidth: parent.width
Layout.fillWidth: true
visible: logic.labelInfoVisible
text: logic.labelInfoText
}
}
ProgressBar {
id: progressBar_reset
anchors.fill: pb_save
from: 0
to: logic.progressBarResetMaximium
value: logic.progressBarResetValue
visible: logic.progressBarResetVisible
background: Rectangle {
implicitWidth: parent.width
implicitHeight: parent.height
color: "#100A44"
radius: 4
}
contentItem: Item {
implicitWidth: parent.width
implicitHeight: parent.height
Rectangle {
width: progressBar_reset.visualPosition * parent.width
height: parent.height
radius: 4
color: Qt.rgba(255, 255, 255, 0.15);
}
}
LabelType {
anchors.left: parent.left
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
text: logic.progressBarText
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
font.family: "Lato"
font.styleName: "normal"
font.pixelSize: 16
color: "#D4D4D4"
visible: logic.progressBarTextVisible
}
}
BlueButtonType {
id: pb_save
enabled: logic.pageEnabled
anchors.horizontalCenter: parent.horizontalCenter
anchors.bottom: root.bottom
anchors.bottomMargin: 20
width: root.width - 60
height: 40
text: qsTr("Save and restart VPN")
visible: logic.pushButtonSaveVisible
onClicked: {
logic.onPushButtonSaveClicked()
}
}
BlueButtonType {
anchors.fill: pb_save
text: qsTr("Cancel")
visible: logic.pushButtonCancelVisible
enabled: logic.pushButtonCancelVisible
onClicked: {
logic.onPushButtonCancelClicked()
}
}
}
+2
View File
@@ -72,6 +72,7 @@
#include "pages_logic/protocols/ShadowSocksLogic.h"
#include "pages_logic/protocols/OtherProtocolsLogic.h"
#include "pages_logic/protocols/WireGuardLogic.h"
#include "pages_logic/protocols/V2RayLogic.h"
using namespace amnezia;
using namespace PageEnumNS;
@@ -93,6 +94,7 @@ UiLogic::UiLogic(std::shared_ptr<Settings> settings, std::shared_ptr<VpnConfigur
m_protocolLogicMap.insert(Proto::ShadowSocks, new ShadowSocksLogic(this));
m_protocolLogicMap.insert(Proto::Cloak, new CloakLogic(this));
m_protocolLogicMap.insert(Proto::WireGuard, new WireGuardLogic(this));
m_protocolLogicMap.insert(Proto::V2Ray, new V2RayLogic(this));
m_protocolLogicMap.insert(Proto::Dns, new OtherProtocolsLogic(this));
m_protocolLogicMap.insert(Proto::Sftp, new OtherProtocolsLogic(this));
+2
View File
@@ -49,6 +49,7 @@ class PageProtocolLogicBase;
class OpenVpnLogic;
class ShadowSocksLogic;
class CloakLogic;
class V2RayLogic;
class OtherProtocolsLogic;
@@ -94,6 +95,7 @@ public:
friend class OpenVpnLogic;
friend class ShadowSocksLogic;
friend class CloakLogic;
friend class V2RayLogic;
friend class OtherProtocolsLogic;
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
Binary file not shown.
Binary file not shown.