Files
amnezia-client/client/core/openvpnconfigurator.cpp
T

256 lines
8.3 KiB
C++
Raw Normal View History

2020-12-18 14:57:22 +03:00
#include "openvpnconfigurator.h"
#include <QApplication>
#include <QProcess>
#include <QString>
#include <QRandomGenerator>
#include <QTemporaryDir>
#include <QDebug>
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;
}
QString OpenVpnConfigurator::getEasyRsaShPath()
{
2021-01-07 20:53:42 +03:00
#ifdef Q_OS_WIN
// easyrsa sh path should looks like
// "/Program Files (x86)/AmneziaVPN/easyrsa/easyrsa"
2020-12-18 14:57:22 +03:00
QString easyRsaShPath = QDir::toNativeSeparators(QApplication::applicationDirPath()) + "\\easyrsa\\easyrsa";
2021-03-06 15:07:43 +03:00
// easyRsaShPath.replace("C:\\", "/cygdrive/c/");
// easyRsaShPath.replace("\\", "/");
easyRsaShPath = "\"" + easyRsaShPath + "\"";
2020-12-18 14:57:22 +03:00
2021-03-06 15:07:43 +03:00
// 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\"";
2021-01-07 20:53:42 +03:00
#else
2021-01-08 15:43:45 +03:00
return QDir::toNativeSeparators(QApplication::applicationDirPath()) + "/easyrsa";
2021-01-07 20:53:42 +03:00
#endif
2020-12-18 14:57:22 +03:00
}
QProcessEnvironment OpenVpnConfigurator::prepareEnv()
{
QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
QString pathEnvVar = env.value("PATH");
2021-01-08 15:43:45 +03:00
#ifdef Q_OS_WIN
2021-03-06 15:07:43 +03:00
pathEnvVar.clear();
2020-12-18 14:57:22 +03:00
pathEnvVar.prepend(QDir::toNativeSeparators(QApplication::applicationDirPath()) + "\\easyrsa\\bin;");
2021-01-08 00:34:15 +03:00
pathEnvVar.prepend(QDir::toNativeSeparators(QApplication::applicationDirPath()) + "\\openvpn\\i386;");
pathEnvVar.prepend(QDir::toNativeSeparators(QApplication::applicationDirPath()) + "\\openvpn\\x64;");
2021-01-08 15:43:45 +03:00
#else
pathEnvVar.prepend(QDir::toNativeSeparators(QApplication::applicationDirPath()) + "/Contents/MacOS");
#endif
2020-12-18 14:57:22 +03:00
env.insert("PATH", pathEnvVar);
2021-03-06 15:07:43 +03:00
//qDebug().noquote() << "ENV PATH" << pathEnvVar;
2020-12-18 14:57:22 +03:00
return env;
}
2021-01-08 15:43:45 +03:00
ErrorCode OpenVpnConfigurator::initPKI(const QString &path)
2020-12-18 14:57:22 +03:00
{
QProcess p;
p.setProcessChannelMode(QProcess::MergedChannels);
2021-01-08 15:43:45 +03:00
#ifdef Q_OS_WIN
2021-01-11 16:41:17 +03:00
p.setProcessEnvironment(prepareEnv());
2021-01-08 15:43:45 +03:00
p.setProgram("cmd.exe");
2021-03-06 15:07:43 +03:00
p.setNativeArguments(QString("/C \"ash.exe %1\"").arg(getEasyRsaShPath() + " init-pki"));
qDebug().noquote() << "EasyRsa tmp path" << path;
qDebug().noquote() << "EasyRsa args" << p.nativeArguments();
2021-01-08 15:43:45 +03:00
#else
p.setProgram(getEasyRsaShPath());
p.setArguments(QStringList() << "init-pki");
#endif
2020-12-18 14:57:22 +03:00
p.setWorkingDirectory(path);
2021-03-06 15:07:43 +03:00
QObject::connect(&p, &QProcess::channelReadyRead, [&](){
qDebug().noquote() << "Init PKI" << p.readAll();
});
2021-01-08 15:43:45 +03:00
p.start();
2020-12-18 14:57:22 +03:00
p.waitForFinished();
2021-01-08 15:43:45 +03:00
if (p.exitCode() == 0) return ErrorCode::NoError;
else return ErrorCode::EasyRsaError;
2020-12-18 14:57:22 +03:00
}
2021-01-08 15:43:45 +03:00
ErrorCode OpenVpnConfigurator::genReq(const QString &path, const QString &clientId)
2020-12-18 14:57:22 +03:00
{
QProcess p;
p.setProcessChannelMode(QProcess::MergedChannels);
2021-01-08 15:43:45 +03:00
#ifdef Q_OS_WIN
2021-01-11 16:41:17 +03:00
p.setProcessEnvironment(prepareEnv());
2021-01-08 15:43:45 +03:00
p.setProgram("cmd.exe");
2021-03-06 15:07:43 +03:00
p.setNativeArguments(QString("/C \"ash.exe %1\"").arg(getEasyRsaShPath() + " gen-req " + clientId + " nopass"));
qDebug().noquote() << "EasyRsa args" << p.nativeArguments();
2021-01-08 15:43:45 +03:00
#else
p.setArguments(QStringList() << "gen-req" << clientId << "nopass");
p.setProgram(getEasyRsaShPath());
#endif
2020-12-18 14:57:22 +03:00
p.setWorkingDirectory(path);
QObject::connect(&p, &QProcess::channelReadyRead, [&](){
QString data = p.readAll();
2021-03-06 15:07:43 +03:00
qDebug().noquote() << data;
2020-12-18 14:57:22 +03:00
if (data.contains("Common Name (eg: your user, host, or server name)")) {
p.write("\n");
}
});
2021-01-08 15:43:45 +03:00
p.start();
2020-12-18 14:57:22 +03:00
p.waitForFinished();
2021-01-08 15:43:45 +03:00
if (p.exitCode() == 0) return ErrorCode::NoError;
else return ErrorCode::EasyRsaError;
2020-12-18 14:57:22 +03:00
}
OpenVpnConfigurator::ConnectionData OpenVpnConfigurator::createCertRequest()
{
OpenVpnConfigurator::ConnectionData connData;
connData.clientId = getRandomString(32);
QTemporaryDir dir;
// if (dir.isValid()) {
// // dir.path() returns the unique directory path
// }
2020-12-18 14:57:22 +03:00
QString path = dir.path();
initPKI(path);
2021-01-08 15:43:45 +03:00
ErrorCode errorCode = genReq(path, connData.clientId);
2020-12-18 14:57:22 +03:00
Q_UNUSED(errorCode)
2020-12-18 14:57:22 +03:00
QFile req(path + "/pki/reqs/" + connData.clientId + ".req");
req.open(QIODevice::ReadOnly);
connData.request = req.readAll();
QFile key(path + "/pki/private/" + connData.clientId + ".key");
key.open(QIODevice::ReadOnly);
connData.privKey = key.readAll();
// qDebug().noquote() << connData.request;
// qDebug().noquote() << connData.privKey;
2020-12-18 14:57:22 +03:00
return connData;
}
2021-01-15 23:36:35 +03:00
OpenVpnConfigurator::ConnectionData OpenVpnConfigurator::prepareOpenVpnConfig(const ServerCredentials &credentials,
Protocol proto, ErrorCode *errorCode)
2020-12-18 14:57:22 +03:00
{
OpenVpnConfigurator::ConnectionData connData = OpenVpnConfigurator::createCertRequest();
2021-01-06 17:12:24 +03:00
connData.host = credentials.hostName;
2020-12-18 14:57:22 +03:00
2021-01-07 20:53:42 +03:00
if (connData.privKey.isEmpty() || connData.request.isEmpty()) {
2021-01-15 23:36:35 +03:00
if (errorCode) *errorCode = ErrorCode::EasyRsaExecutableMissing;
2021-01-07 20:53:42 +03:00
return connData;
}
2020-12-18 14:57:22 +03:00
QString reqFileName = QString("/opt/amneziavpn_data/clients/%1.req").arg(connData.clientId);
2021-01-15 23:36:35 +03:00
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;
}
ErrorCode e = ServerController::uploadTextFileToContainer(container, credentials, connData.request, reqFileName);
2021-01-06 17:12:24 +03:00
if (e) {
2021-01-15 23:36:35 +03:00
if (errorCode) *errorCode = e;
2021-01-06 17:12:24 +03:00
return connData;
}
2020-12-18 14:57:22 +03:00
2021-01-15 23:36:35 +03:00
e = ServerController::signCert(container, credentials, connData.clientId);
if (e) {
if (errorCode) *errorCode = e;
return connData;
}
2020-12-18 14:57:22 +03:00
2021-01-15 23:36:35 +03:00
connData.caCert = ServerController::getTextFileFromContainer(container, credentials, ServerController::caCertPath(), &e);
connData.clientCert = ServerController::getTextFileFromContainer(container, credentials, ServerController::clientCertPath() + QString("%1.crt").arg(connData.clientId), &e);
2021-01-06 17:12:24 +03:00
if (e) {
2021-01-15 23:36:35 +03:00
if (errorCode) *errorCode = e;
2021-01-06 17:12:24 +03:00
return connData;
}
2020-12-18 14:57:22 +03:00
2021-01-15 23:36:35 +03:00
connData.taKey = ServerController::getTextFileFromContainer(container, credentials, ServerController::taKeyPath(), &e);
if (connData.caCert.isEmpty() || connData.clientCert.isEmpty() || connData.taKey.isEmpty()) {
if (errorCode) *errorCode = ErrorCode::RemoteProcessCrashError;
}
2020-12-18 14:57:22 +03:00
2021-01-21 19:14:07 +03:00
ServerController::setupServerFirewall(credentials);
2020-12-18 14:57:22 +03:00
return connData;
}
2021-02-18 15:00:41 +03:00
Settings &OpenVpnConfigurator::m_settings()
{
static Settings s;
return s;
}
2021-01-15 23:36:35 +03:00
QString OpenVpnConfigurator::genOpenVpnConfig(const ServerCredentials &credentials,
Protocol proto, ErrorCode *errorCode)
2020-12-18 14:57:22 +03:00
{
2021-01-15 23:36:35 +03:00
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");
}
2020-12-18 14:57:22 +03:00
configTemplFile.open(QIODevice::ReadOnly);
QString config = configTemplFile.readAll();
2021-01-15 23:36:35 +03:00
ConnectionData connData = prepareOpenVpnConfig(credentials, proto, errorCode);
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()));
}
2020-12-18 14:57:22 +03:00
2021-02-18 15:00:41 +03:00
config.replace("$PRIMARY_DNS", m_settings().primaryDns());
config.replace("$SECONDARY_DNS", m_settings().secondaryDns());
if (m_settings().customRouting()) {
config.replace("redirect-gateway def1 bypass-dhcp", "");
}
2020-12-18 14:57:22 +03:00
config.replace("$REMOTE_HOST", connData.host);
config.replace("$REMOTE_PORT", "1194");
config.replace("$CA_CERT", connData.caCert);
config.replace("$CLIENT_CERT", connData.clientCert);
config.replace("$PRIV_KEY", connData.privKey);
config.replace("$TA_KEY", connData.taKey);
2021-02-21 09:44:53 -08:00
#ifdef Q_OS_MAC
config.replace("block-outside-dns", "");
#endif
2021-02-18 15:00:41 +03:00
//qDebug().noquote() << config;
2020-12-18 14:57:22 +03:00
return config;
}