Merge pull request #38 from amnezia-vpn/wireguard_embedded

change wireguard vpn protocol implementation on Windows from wg.exe t…
This commit is contained in:
pokamest 2021-10-27 01:32:42 +03:00 committed by GitHub
commit b124aabf69
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 266 additions and 61 deletions

View file

@ -6,6 +6,11 @@
#include <QDebug>
#include <QTemporaryFile>
#include <openssl/rand.h>
#include <openssl/rsa.h>
#include <openssl/x509.h>
#include <openssl/pem.h>
#include "sftpdefs.h"
#include "core/server_defs.h"
@ -13,72 +18,34 @@
#include "core/scripts_registry.h"
#include "utils.h"
QProcessEnvironment WireguardConfigurator::prepareEnv()
{
QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
QString pathEnvVar = env.value("PATH");
#ifdef Q_OS_WIN
pathEnvVar.clear();
pathEnvVar.prepend(QDir::toNativeSeparators(QApplication::applicationDirPath()) + "\\wireguard;");
#else
pathEnvVar.prepend(QDir::toNativeSeparators(QApplication::applicationDirPath()) + "/Contents/MacOS");
#endif
env.insert("PATH", pathEnvVar);
qDebug().noquote() << "ENV PATH" << pathEnvVar;
return env;
}
WireguardConfigurator::ConnectionData WireguardConfigurator::genClientKeys()
{
// TODO review
constexpr size_t EDDSA_KEY_LENGTH = 32;
ConnectionData connData;
QString program;
#ifdef Q_OS_WIN
program = QDir::toNativeSeparators(QApplication::applicationDirPath()) + "\\wireguard\\wg.exe";
#else
program = QDir::toNativeSeparators(QApplication::applicationDirPath()) + "/Contents/MacOS/wg";
#endif
unsigned char buff[EDDSA_KEY_LENGTH];
int ret = RAND_priv_bytes(buff, EDDSA_KEY_LENGTH);
if (ret <=0) return connData;
#ifndef Q_OS_IOS
EVP_PKEY * pKey = EVP_PKEY_new();
q_check_ptr(pKey);
pKey = EVP_PKEY_new_raw_private_key(EVP_PKEY_ED25519, NULL, &buff[0], EDDSA_KEY_LENGTH);
// Priv
{
QProcess p;
p.setProcessEnvironment(prepareEnv());
p.setProcessChannelMode(QProcess::MergedChannels);
p.setProgram(program);
p.setArguments(QStringList() << "genkey");
size_t keySize = EDDSA_KEY_LENGTH;
p.start();
p.waitForFinished();
// save private key
unsigned char priv[EDDSA_KEY_LENGTH];
EVP_PKEY_get_raw_private_key(pKey, priv, &keySize);
connData.clientPrivKey = QByteArray::fromRawData((char*)priv, keySize).toBase64();
connData.clientPrivKey = QString(p.readAll());
connData.clientPrivKey.replace("\r", "");
connData.clientPrivKey.replace("\n", "");
}
// save public key
unsigned char pub[EDDSA_KEY_LENGTH];
EVP_PKEY_get_raw_public_key(pKey, pub, &keySize);
connData.clientPubKey = QByteArray::fromRawData((char*)pub, keySize).toBase64();
// Pub
{
QProcess p;
p.setProcessEnvironment(prepareEnv());
p.setProcessChannelMode(QProcess::MergedChannels);
p.setProgram(program);
p.setArguments(QStringList() << "pubkey");
p.start();
p.write(connData.clientPrivKey.toUtf8());
p.closeWriteChannel();
p.waitForFinished();
connData.clientPubKey = QString(p.readAll());
connData.clientPubKey.replace("\r", "");
connData.clientPubKey.replace("\n", "");
}
#endif
return connData;
}

View file

@ -28,8 +28,6 @@ public:
private:
static QProcessEnvironment prepareEnv();
static ConnectionData prepareWireguardConfig(const ServerCredentials &credentials,
DockerContainer container, ErrorCode *errorCode = nullptr);

View file

@ -51,7 +51,7 @@ void WireguardProtocol::stop()
m_wireguardStopProcess->setProgram(wireguardExecPath());
QStringList arguments({"/uninstalltunnelservice", serviceName(), });
QStringList arguments({"--remove", configPath()});
m_wireguardStopProcess->setArguments(arguments);
qDebug() << arguments.join(" ");
@ -114,7 +114,7 @@ void WireguardProtocol::updateRouteGateway(QString line)
QString WireguardProtocol::wireguardExecPath() const
{
#ifdef Q_OS_WIN
return Utils::executable("wireguard/wireguard", true);
return Utils::executable("wireguard/wireguard-service", true);
#elif defined Q_OS_LINUX
return Utils::usrExecutable("wg");
#else
@ -163,7 +163,7 @@ ErrorCode WireguardProtocol::start()
m_wireguardStartProcess->setProgram(wireguardExecPath());
QStringList arguments({"/installtunnelservice", configPath(), });
QStringList arguments({"--add", configPath()});
m_wireguardStartProcess->setArguments(arguments);
qDebug() << arguments.join(" ");

View file

@ -82,6 +82,7 @@ signtool sign /v /sm /s My /n "Privacy Technologies OU" /fd sha256 /tr http://ti
echo "Copying deploy data..."
xcopy %DEPLOY_DATA_DIR% %OUT_APP_DIR% /s /e /y /i /f
copy "%WORK_DIR:"=%\service\wireguard-service\release\wireguard-service.exe" %OUT_APP_DIR%\wireguard\
del %OUT_APP_DIR%\botand.dll

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -4,4 +4,7 @@
include(common.pri)
qtservice-uselib:SUBDIRS=buildlib
SUBDIRS+=server
win32 {
SUBDIRS+=wireguard-service
}
}

View file

@ -0,0 +1,31 @@
#include "wireguardtunnelservice.h"
#include <strsafe.h>
#include <Windows.h>
int wmain(int argc, wchar_t** argv)
{
if (argc != 3) {
debug_log(L"Wrong argument provided");
return 1;
}
TCHAR option[20];
TCHAR configFile[5000];
StringCchCopy(option, 20, argv[1]);
StringCchCopy(configFile, 5000, argv[2]);
WireguardTunnelService tunnel(configFile);
if (lstrcmpi(option, TEXT("--run")) == 0) {
debug_log(L"start tunnel");
tunnel.startTunnel();
} else if (lstrcmpi(option, TEXT("--add")) == 0) {
tunnel.addService();
} else if (lstrcmpi(option, TEXT("--remove")) == 0) {
tunnel.removeService();
} else {
debug_log(L"Wrong argument provided");
return 1;
}
return 0;
}

View file

@ -0,0 +1,23 @@
TARGET = wireguard-service
TEMPLATE = app
CONFIG += console
CONFIG -= app_bundle
CONFIG -= qt
LIBS += \
-luser32 \
-lrasapi32 \
-lshlwapi \
-liphlpapi \
-lws2_32 \
-liphlpapi \
-lgdi32 \
-lAdvapi32 \
-lKernel32
HEADERS = \
wireguardtunnelservice.h
SOURCES = \
main.cpp \
wireguardtunnelservice.cpp

View file

@ -0,0 +1,160 @@
#include "wireguardtunnelservice.h"
#include <Windows.h>
#include <thread>
#include <chrono>
#include <strsafe.h>
#include <iostream>
#include <fstream>
#include <stdint.h>
void debug_log(const std::wstring& msg)
{
std::wcerr << msg << std::endl;
}
WireguardTunnelService::WireguardTunnelService(const std::wstring& configFile):
m_configFile{configFile}
{
}
void WireguardTunnelService::addService()
{
SC_HANDLE scm;
SC_HANDLE service;
scm = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
if (NULL == scm) {
debug_log(L"OpenSCManager failed");
return;
}
WCHAR szFileName[MAX_PATH];
GetModuleFileNameW(NULL, szFileName, MAX_PATH);
std::wstring runCommand = szFileName;
runCommand += TEXT(" --run ");
runCommand += m_configFile;
debug_log(runCommand);
// check if service is already running
service = OpenServiceW(
scm,
SVCNAME,
SERVICE_ALL_ACCESS
);
if (NULL != service) {
//service is already running, remove it before add new service
debug_log(L"service is already running, remove it before add new service");
CloseServiceHandle(service);
removeService();
}
service = CreateServiceW(
scm,
SVCNAME,
SVCNAME,
SERVICE_ALL_ACCESS,
SERVICE_WIN32_OWN_PROCESS,
SERVICE_DEMAND_START,
SERVICE_ERROR_NORMAL,
runCommand.c_str(),
NULL,
NULL,
TEXT("Nsi\0TcpIp"),
NULL,
NULL);
if (NULL == service) {
debug_log(L"CreateServiceW failed");
CloseServiceHandle(scm);
return;
}
SERVICE_SID_INFO info;
info.dwServiceSidType = SERVICE_SID_TYPE_UNRESTRICTED;
if (ChangeServiceConfig2W(service,
SERVICE_CONFIG_SERVICE_SID_INFO,
&info) == 0) {
debug_log(L"ChangeServiceConfig2 failed");
CloseServiceHandle(service);
CloseServiceHandle(scm);
return;
}
if (StartServiceW(service, 0, NULL) == 0) {
debug_log(L"StartServiceW failed");
CloseServiceHandle(service);
CloseServiceHandle(scm);
return;
}
if (DeleteService(service) == 0) {
debug_log(L"DeleteService failed");
CloseServiceHandle(service);
CloseServiceHandle(scm);
return;
}
CloseServiceHandle(service);
CloseServiceHandle(scm);
}
void WireguardTunnelService::removeService()
{
SC_HANDLE scm;
SC_HANDLE service;
scm = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
if (NULL == scm) {
debug_log(L"OpenSCManager failed");
return;
}
service = OpenServiceW(
scm,
SVCNAME,
SERVICE_ALL_ACCESS
);
if (NULL == service) {
debug_log(L"OpenServiceW failed");
CloseServiceHandle(scm);
return;
}
SERVICE_STATUS stt;
if (ControlService(service, SERVICE_CONTROL_STOP, &stt) == 0) {
debug_log(L"ControlService failed");
DeleteService(service);
CloseServiceHandle(service);
CloseServiceHandle(scm);
return;
}
for (int i = 0;
i < 180 && QueryServiceStatus(scm, &stt) && stt.dwCurrentState != SERVICE_STOPPED;
++i) {
std::this_thread::sleep_for(std::chrono::seconds{1});
}
DeleteService(service);
CloseServiceHandle(service);
CloseServiceHandle(scm);
}
int WireguardTunnelService::startTunnel()
{
debug_log(TEXT(__FUNCTION__));
HMODULE tunnelLib = LoadLibrary(TEXT("tunnel.dll"));
if (!tunnelLib) {
debug_log(L"Failed to load tunnel.dll");
return 1;
}
typedef bool WireGuardTunnelService(const LPCWSTR settings);
WireGuardTunnelService* tunnelProc = (WireGuardTunnelService*)GetProcAddress(
tunnelLib, "WireGuardTunnelService");
if (!tunnelProc) {
debug_log(L"Failed to get WireGuardTunnelService function");
return 1;
}
debug_log(m_configFile.c_str());
if (!tunnelProc(m_configFile.c_str())) {
debug_log(L"Failed to activate the tunnel service");
return 1;
}
return 0;
}

View file

@ -0,0 +1,22 @@
#ifndef WIREGUARDTUNNELSERVICE_H
#define WIREGUARDTUNNELSERVICE_H
#include <Windows.h>
#include <string>
#define SVCNAME TEXT("AmneziaVPNWireGuardService")
class WireguardTunnelService
{
public:
WireguardTunnelService(const std::wstring& configFile);
void addService();
void removeService();
int startTunnel();
private:
std::wstring m_configFile;
};
void debug_log(const std::wstring& msg);
#endif // WIREGUARDTUNNELSERVICE_H