From b4007038fb957102c8de80df23903eb74f84cc54 Mon Sep 17 00:00:00 2001 From: pokamest Date: Wed, 13 Oct 2021 15:46:00 +0300 Subject: [PATCH] ikev2 winapi test solution --- client/main.cpp | 1 + client/protocols/ikev2_vpn_protocol.cpp | 446 +++++++++++++++++++----- client/protocols/ikev2_vpn_protocol.h | 47 ++- 3 files changed, 397 insertions(+), 97 deletions(-) diff --git a/client/main.cpp b/client/main.cpp index 8fd339c0..1cf71d10 100644 --- a/client/main.cpp +++ b/client/main.cpp @@ -116,6 +116,7 @@ int main(int argc, char *argv[]) app.setQuitOnLastWindowClosed(false); + qRegisterMetaType("VpnProtocol::ConnectionState"); qRegisterMetaType("DockerContainer"); qRegisterMetaType("TransportProto"); qRegisterMetaType("Protocol"); diff --git a/client/protocols/ikev2_vpn_protocol.cpp b/client/protocols/ikev2_vpn_protocol.cpp index dc60be39..0d4fc4de 100644 --- a/client/protocols/ikev2_vpn_protocol.cpp +++ b/client/protocols/ikev2_vpn_protocol.cpp @@ -1,14 +1,20 @@ #include #include #include -#include -#include +//#include +//#include #include +#include + #include "debug.h" #include "ikev2_vpn_protocol.h" #include "utils.h" +static std::atomic_connection_state; +static std::mutex mtx; +static std::condition_variable cv; +static std::atomic_bool newEvent{false}; Ikev2Protocol::Ikev2Protocol(const QJsonObject &configuration, QObject* parent) : VpnProtocol(configuration, parent) @@ -20,30 +26,40 @@ Ikev2Protocol::Ikev2Protocol(const QJsonObject &configuration, QObject* parent) Ikev2Protocol::~Ikev2Protocol() { qDebug() << "IpsecProtocol::~IpsecProtocol()"; +#ifdef Q_OS_WIN + _stoped.store(true); + disconnect_vpn(); +#endif Ikev2Protocol::stop(); QThread::msleep(200); + _th_conn_state->join(); + _thr->join(); } void Ikev2Protocol::stop() { #ifdef Q_OS_WINDOWS { - setConnectionState(Disconnecting); + _stoped.store(true); + //setConnectionState(Disconnecting); - auto disconnectProcess = new QProcess; + //auto disconnectProcess = new QProcess; - disconnectProcess->setProgram("rasdial"); - QString arguments = QString("\"%1\" /disconnect") - .arg(tunnelName()); - disconnectProcess->setNativeArguments(arguments); + // disconnectProcess->setProgram("rasdial"); + // QString arguments = QString("\"%1\" /disconnect") + // .arg(tunnelName()); + // disconnectProcess->setNativeArguments(arguments); -// connect(connectProcess, &QProcess::readyRead, [connectProcess]() { -// qDebug().noquote() << "connectProcess readyRead" << connectProcess->readAll(); -// }); + // // connect(connectProcess, &QProcess::readyRead, [connectProcess]() { + // // qDebug().noquote() << "connectProcess readyRead" << connectProcess->readAll(); + // // }); - disconnectProcess->start(); - disconnectProcess->waitForFinished(5000); - setConnectionState(Disconnected); + // disconnectProcess->start(); + // disconnectProcess->waitForFinished(5000); + // setConnectionState(Disconnected); + if (! disconnect_vpn() ){ + qDebug()<<"We don't disconnect"; + } } #endif } @@ -57,7 +73,7 @@ ErrorCode Ikev2Protocol::start() { #ifdef Q_OS_WINDOWS QByteArray cert = QByteArray::fromBase64(m_config[config_key::cert].toString().toUtf8()); - setConnectionState(ConnectionState::Connecting); + setConnectionState(Connecting); QTemporaryFile certFile; certFile.setAutoRemove(false); @@ -65,7 +81,6 @@ ErrorCode Ikev2Protocol::start() certFile.write(cert); certFile.close(); - { auto certInstallProcess = IpcClient::CreatePrivilegedProcess(); @@ -87,37 +102,48 @@ ErrorCode Ikev2Protocol::start() }); certInstallProcess->setArguments(arguments); -// qDebug() << arguments.join(" "); -// connect(certInstallProcess.data(), &IpcProcessInterfaceReplica::errorOccurred, [certInstallProcess](QProcess::ProcessError error) { -// qDebug() << "IpcProcessInterfaceReplica errorOccurred" << error; -// }); + // qDebug() << arguments.join(" "); + // connect(certInstallProcess.data(), &IpcProcessInterfaceReplica::errorOccurred, [certInstallProcess](QProcess::ProcessError error) { + // qDebug() << "IpcProcessInterfaceReplica errorOccurred" << error; + // }); -// connect(certInstallProcess.data(), &IpcProcessInterfaceReplica::stateChanged, [certInstallProcess](QProcess::ProcessState newState) { -// qDebug() << "IpcProcessInterfaceReplica stateChanged" << newState; -// }); + // connect(certInstallProcess.data(), &IpcProcessInterfaceReplica::stateChanged, [certInstallProcess](QProcess::ProcessState newState) { + // qDebug() << "IpcProcessInterfaceReplica stateChanged" << newState; + // }); -// connect(certInstallProcess.data(), &IpcProcessInterfaceReplica::readyRead, [certInstallProcess]() { -// auto req = certInstallProcess->readAll(); -// req.waitForFinished(); -// qDebug() << "IpcProcessInterfaceReplica readyRead" << req.returnValue(); -// }); + // connect(certInstallProcess.data(), &IpcProcessInterfaceReplica::readyRead, [certInstallProcess]() { + // auto req = certInstallProcess->readAll(); + // req.waitForFinished(); + // qDebug() << "IpcProcessInterfaceReplica readyRead" << req.returnValue(); + // }); certInstallProcess->start(); } - + // /* { - auto adapterRemoveProcess = new QProcess; +// auto adapterRemoveProcess = new QProcess; - adapterRemoveProcess->setProgram("powershell"); - QString arguments = QString("-command \"Remove-VpnConnection -Name '%1' -Force\"").arg(tunnelName()); - adapterRemoveProcess->setNativeArguments(arguments); +// adapterRemoveProcess->setProgram("powershell"); +// QString arguments = QString("-command \"Remove-VpnConnection -Name '%1' -Force\"").arg(tunnelName()); +// adapterRemoveProcess->setNativeArguments(arguments); - adapterRemoveProcess->start(); - adapterRemoveProcess->waitForFinished(5000); +// adapterRemoveProcess->start(); +// adapterRemoveProcess->waitForFinished(5000); + if ( disconnect_vpn()){ + qDebug()<<"VPN was disconnected"; + } + if ( delete_vpn_connection (tunnelName())){ + qDebug()<<"VPN was deleted"; + } } { +// { +// if ( !create_new_vpn(tunnelName(), m_config[config_key::hostName].toString())){ +// qDebug() <<"Can't create the VPN connect"; +// } +// } auto adapterInstallProcess = new QProcess; adapterInstallProcess->setProgram("powershell"); @@ -128,13 +154,9 @@ ErrorCode Ikev2Protocol::start() "-AuthenticationMethod MachineCertificate " "-EncryptionLevel Required " "-PassThru\"") - .arg(m_config[config_key::hostName].toString()) - .arg(tunnelName()); + .arg(m_config[config_key::hostName].toString()) + .arg(tunnelName()); adapterInstallProcess->setNativeArguments(arguments); -// connect(adapterInstallProcess, &QProcess::readyRead, [adapterInstallProcess]() { -// qDebug().noquote() << "adapterInstallProcess readyRead" << adapterInstallProcess->readAll(); -// }); - adapterInstallProcess->start(); adapterInstallProcess->waitForFinished(5000); } @@ -152,67 +174,313 @@ ErrorCode Ikev2Protocol::start() "-PfsGroup None " "-DHGroup Group14 " "-PassThru -Force\"") - .arg(tunnelName()); + .arg(tunnelName()); adapterConfigProcess->setNativeArguments(arguments); -// connect(adapterConfigProcess, &QProcess::readyRead, [adapterConfigProcess]() { -// qDebug().noquote() << "adapterConfigProcess readyRead" << adapterConfigProcess->readAll(); -// }); + // connect(adapterConfigProcess, &QProcess::readyRead, [adapterConfigProcess]() { + // qDebug().noquote() << "adapterConfigProcess readyRead" << adapterConfigProcess->readAll(); + // }); adapterConfigProcess->start(); adapterConfigProcess->waitForFinished(5000); } - + //*/ { -// char buf[RASBUFFER]= {0}; -// DWORD err = 0; -// RASDIALPARAMSA *param = (RASDIALPARAMSA *)buf; -// param->dwSize = 1064; -// strcpy(param->szEntryName, tunnelName().toStdString().c_str()); -// err = RasDialA(NULL, NULL, param, 0, (LPVOID)rasCallback, &g_h); -// qDebug() << "Ikev2Protocol::start() ret" << err; - - - auto connectProcess = new QProcess; - - connectProcess->setProgram("rasdial"); - QString arguments = QString("\"%1\"") - .arg(tunnelName()); - connectProcess->setNativeArguments(arguments); - - connect(connectProcess, &QProcess::readyRead, [connectProcess]() { - qDebug().noquote() << "connectProcess readyRead" << connectProcess->readAll(); - }); - - connectProcess->start(); - connectProcess->waitForFinished(5000); + if (connect_to_vpn(tunnelName())){ + _thr = std::make_unique(&Ikev2Protocol::_ikev2_states, this); + }else{ + qDebug()<<"We can't connect to VPN"; + } } - - setConnectionState(Connected); + //setConnectionState(Connecting); + return ErrorCode::NoError; +#else return ErrorCode::NoError; - #endif - return ErrorCode::NoError; } +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +void Ikev2Protocol::conn_state(){ + + while ( _stoped != true){ + if (hRasConn != nullptr){ + RASCONNSTATUS cs; + cs.dwSize = sizeof(RASCONNSTATUS); + RasGetConnectStatus(hRasConn, &cs); + qDebug()<<"Current state RAS= "<< cs.rasconnstate; + if (cs.rasconnstate == RASCS_DONE)//connected + { + setConnectionState(Connected); + } + if (cs.rasconnstate == 0)//disconnected + { + setConnectionState(Disconnected); + } + } + std::this_thread::sleep_for(std::chrono::seconds(5)); + } +} +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +#ifdef Q_OS_WINDOWS +//bool Ikev2Protocol::create_new_vpn(const QString & vpn_name, +// const QString & serv_addr){ + +// if ( RasValidateEntryName(nullptr, vpn_name.toStdWString().c_str()) != ERROR_SUCCESS) +// return false; +// DWORD size = 0; +// ::RasGetEntryProperties(nullptr, L"", nullptr, &size, nullptr, nullptr); +// LPRASENTRY pras = static_cast(malloc(size)); +// memset(pras, 0, size); +// pras->dwSize = size; +// pras->dwType = RASET_Vpn; +// pras->dwRedialCount = 1; +// pras->dwRedialPause = 60; +// pras->dwfNetProtocols = RASNP_Ip|RASNP_Ipv6; +// pras->dwEncryptionType = ET_RequireMax; +// wcscpy_s(pras->szLocalPhoneNumber, serv_addr.toStdWString().c_str()); +// wcscpy_s(pras->szDeviceType, RASDT_Vpn); +// pras->dwfOptions = RASEO_RemoteDefaultGateway; +// pras->dwfOptions |= RASEO_RequireDataEncryption; +// pras->dwfOptions2 |= RASEO2_RequireMachineCertificates; +// pras->dwVpnStrategy = VS_Ikev2Only; +// const auto nRet = ::RasSetEntryProperties(nullptr, vpn_name.toStdWString().c_str(), pras, pras->dwSize, NULL, 0); +// free(pras); +// if (nRet == ERROR_SUCCESS) +// return true; +// return false; +//} +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +bool Ikev2Protocol::delete_vpn_connection(const QString &vpn_name){ + + if ( RasDeleteEntry(nullptr, vpn_name.toStdWString().c_str()) == ERROR_SUCCESS){ + return true; + } + return false; +} +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +bool Ikev2Protocol::connect_to_vpn(const QString & vpn_name){ + RASDIALPARAMS RasDialParams; + memset(&RasDialParams, 0x0, sizeof(RASDIALPARAMS)); + RasDialParams.dwSize = sizeof(RASDIALPARAMS); + wcscpy_s(RasDialParams.szEntryName, vpn_name.toStdWString().c_str()); + auto ret = RasDial(NULL, NULL, &RasDialParams, 0, + &Ikev2Protocol::RasDialFuncCallback, + &hRasConn); + if (ret == ERROR_SUCCESS){ + _th_conn_state = std::make_unique(&Ikev2Protocol::conn_state, this); + return true; + } + return false; +} +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +bool Ikev2Protocol::disconnect_vpn(){ + if ( hRasConn != nullptr ){ + if ( RasHangUp(hRasConn) != ERROR_SUCCESS) + return false; + } + return true; +} +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +void Ikev2Protocol::_ikev2_states(){ + + while(!_stoped){ + qDebug()<<"We are waiting the change of RAS state"; + std::unique_lock lck(mtx); + while ( !newEvent ){ + cv.wait(lck); + } + qDebug()<<"Recive the new event "<(_connection_state); + switch (_connection_state) + { + case RASCS_OpenPort: + setConnectionState(Preparing); + qDebug()<<__LINE__; + //printf ("RASCS_OpenPort = %d\n", _connection_state); + //printf ("Opening port...\n"); + break; + case RASCS_PortOpened: + setConnectionState(Preparing); + qDebug()<<__LINE__; + //printf ("RASCS_PortOpened = %d\n", _connection_state); + //printf ("Port opened.\n"); + break; + case RASCS_ConnectDevice: + setConnectionState(Preparing); + qDebug()<<__LINE__; + //printf ("RASCS_ConnectDevice = %d\n", _connection_state); + //printf ("Connecting device...\n"); + break; + case RASCS_DeviceConnected: + setConnectionState(Preparing); + qDebug()<<__LINE__; + //printf ("RASCS_DeviceConnected = %d\n", _connection_state); + //printf ("Device connected.\n"); + break; + case RASCS_AllDevicesConnected: + setConnectionState(Preparing); + qDebug()<<__LINE__; + //printf ("RASCS_AllDevicesConnected = %d\n", _connection_state); + //printf ("All devices connected.\n"); + break; + case RASCS_Authenticate: + setConnectionState(Preparing); + qDebug()<<__LINE__; + //printf ("RASCS_Authenticate = %d\n", _connection_state); + // printf ("Authenticating...\n"); + break; + case RASCS_AuthNotify: + setConnectionState(Disconnected); + qDebug()<<__LINE__; + //printf ("RASCS_AuthNotify = %d\n", _connection_state); + // printf ("Authentication notify.\n"); + break; + case RASCS_AuthRetry: + setConnectionState(Preparing); + qDebug()<<__LINE__; + //printf ("RASCS_AuthRetry = %d\n", _connection_state); + //printf ("Retrying authentication...\n"); + break; + case RASCS_AuthCallback: + qDebug()<<__LINE__; + //printf ("RASCS_AuthCallback = %d\n", _connection_state); + //printf ("Authentication callback...\n"); + break; + case RASCS_AuthChangePassword: + qDebug()<<__LINE__; + // printf ("RASCS_AuthChangePassword = %d\n", _connection_state); + //printf ("Change password...\n"); + break; + case RASCS_AuthProject: + qDebug()<<__LINE__; + //printf ("RASCS_AuthProject = %d\n", _connection_state); + //printf ("Projection phase started...\n"); + break; + case RASCS_AuthLinkSpeed: + qDebug()<<__LINE__; + //printf ("RASCS_AuthLinkSpeed = %d\n", _connection_state); + //printf ("Negoting speed...\n"); + break; + case RASCS_AuthAck: + qDebug()<<__LINE__; + //printf ("RASCS_AuthAck = %d\n", _connection_state); + //printf ("Authentication acknowledge...\n"); + break; + case RASCS_ReAuthenticate: + qDebug()<<__LINE__; + //printf ("RASCS_ReAuthenticate = %d\n", _connection_state); + //printf ("Retrying Authentication...\n"); + break; + case RASCS_Authenticated: + qDebug()<<__LINE__; + //printf ("RASCS_Authenticated = %d\n", _connection_state); + //printf ("Authentication complete.\n"); + break; + case RASCS_PrepareForCallback: + qDebug()<<__LINE__; + //printf ("RASCS_PrepareForCallback = %d\n", _connection_state); + //printf ("Preparing for callback...\n"); + break; + case RASCS_WaitForModemReset: + qDebug()<<__LINE__; + //printf ("RASCS_WaitForModemReset = %d\n", _connection_state); + // printf ("Waiting for modem reset...\n"); + break; + case RASCS_WaitForCallback: + qDebug()<<__LINE__; + //printf ("RASCS_WaitForCallback = %d\n", _connection_state); + //printf ("Waiting for callback...\n"); + break; + case RASCS_Projected: + qDebug()<<__LINE__; + //printf ("RASCS_Projected = %d\n", _connection_state); + //printf ("Projection completed.\n"); + break; +#if (WINVER >= 0x400) + case RASCS_StartAuthentication: // Windows 95 only + qDebug()<<__LINE__; + //printf ("RASCS_StartAuthentication = %d\n", _connection_state); + //printf ("Starting authentication...\n"); + + break; + case RASCS_CallbackComplete: // Windows 95 only + qDebug()<<__LINE__; + //printf ("RASCS_CallbackComplete = %d\n", rasconnstate); + //printf ("Callback complete.\n"); + break; + case RASCS_LogonNetwork: // Windows 95 only + qDebug()<<__LINE__; + //printf ("RASCS_LogonNetwork = %d\n", _connection_state); + //printf ("Login to the network.\n"); + break; +#endif + case RASCS_SubEntryConnected: + qDebug()<<__LINE__; + //printf ("RASCS_SubEntryConnected = %d\n", _connection_state); + //printf ("Subentry connected.\n"); + break; + case RASCS_SubEntryDisconnected: + qDebug()<<__LINE__; + //printf ("RASCS_SubEntryDisconnected = %d\n", _connection_state); + //printf ("Subentry disconnected.\n"); + break; + //PAUSED STATES: + case RASCS_Interactive: + qDebug()<<__LINE__; + //printf ("RASCS_Interactive = %d\n", _connection_state); + //printf ("In Paused state: Interactive mode.\n"); + break; + case RASCS_RetryAuthentication: + qDebug()<<__LINE__; + //printf ("RASCS_RetryAuthentication = %d\n", _connection_state); + //printf ("In Paused state: Retry Authentication...\n"); + break; + case RASCS_CallbackSetByCaller: + qDebug()<<__LINE__; + //printf ("RASCS_CallbackSetByCaller = %d\n", _connection_state); + //printf ("In Paused state: Callback set by Caller.\n"); + break; + case RASCS_PasswordExpired: + setConnectionState(Error); + qDebug()<<__LINE__; + //printf ("RASCS_PasswordExpired = %d\n", _connection_state); + //printf ("In Paused state: Password has expired...\n"); + break; + + case RASCS_Connected: // = RASCS_DONE: + setConnectionState(Connected); + qDebug()<<__LINE__; + //printf ("RASCS_Connected = %d\n", _connection_state); + //printf ("Connection completed.\n"); + //SetEvent(gEvent_handle); + break; + case RASCS_Disconnected: + setConnectionState(Disconnected); + qDebug()<<__LINE__; + //printf ("RASCS_Disconnected = %d\n", _connection_state); + //printf ("Disconnecting...\n"); + break; + default: + qDebug()<<__LINE__; + //printf ("Unknown Status = %d\n", _connection_state); + //printf ("What are you going to do about it?\n"); + break; + } + //reset RAS event + newEvent = false; + } +} +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +#endif #ifdef Q_OS_WINDOWS -DWORD CALLBACK rasCallback(UINT msg, RASCONNSTATE rascs, DWORD err) -{ - if(err != 0) { - printf("Error: %d\n", err); - fflush(stdout); - //g_done = 1; - return 0; // stop the connection. - } else { - //printf("%s\n", rasState(rascs)); - fflush(stdout); - if(rascs == RASCS_Connected) { - printf("Success: Connected\n"); - fflush(stdout); - //g_done = 1; - } - return 1; - } +void WINAPI Ikev2Protocol::RasDialFuncCallback(UINT /*unMsg*/, + RASCONNSTATE rasconnstate, + DWORD dwError ){ + + qDebug() << "Ikev2Protocol::RasDialFuncCallback" << rasconnstate << dwError; + _connection_state = rasconnstate; + newEvent = true; + cv.notify_all(); } + #endif diff --git a/client/protocols/ikev2_vpn_protocol.h b/client/protocols/ikev2_vpn_protocol.h index 7cbae06a..7537370a 100644 --- a/client/protocols/ikev2_vpn_protocol.h +++ b/client/protocols/ikev2_vpn_protocol.h @@ -11,20 +11,26 @@ #include "core/ipcclient.h" #ifdef Q_OS_WIN -#include -#include -#include +#include +#include +#include +#include +#include +#include + +#include #include -#include +#include #include #include +#include + #pragma comment(lib, "shlwapi.lib") #pragma comment(lib, "rasapi32.lib") +#pragma comment(lib, "Crypt32.lib") -#define RASBUFFER 0x1000 -#define RASMAXENUM 0x100 #endif class Ikev2Protocol : public VpnProtocol @@ -43,14 +49,39 @@ public: private: void readIkev2Configuration(const QJsonObject &configuration); +#ifdef Q_OS_WIN + //certificates variables +#endif private: QJsonObject m_config; #ifdef Q_OS_WIN - HRASCONN g_h; - int g_done = 0; + //RAS functions and parametrs + HRASCONN hRasConn{nullptr}; +// bool create_new_vpn(const QString & vpn_name, +// const QString & serv_addr); + bool delete_vpn_connection(const QString &vpn_name); + + bool connect_to_vpn(const QString & vpn_name); + bool disconnect_vpn(); + static void WINAPI RasDialFuncCallback(UINT unMsg, + RASCONNSTATE rasconnstate, + DWORD dwError ); + + + std::unique_ptr _thr{nullptr}; + void _ikev2_states(); + std::atomic_bool _stoped{false}; + + std::unique_ptr_th_conn_state{nullptr}; + void conn_state(); +signals: + //void Ikev2_connected(); + //void Ikev2_disconnected(); + //void Ikev2_state(int); #endif + }; #ifdef Q_OS_WIN