ikev2 winapi test solution

This commit is contained in:
pokamest 2021-10-13 15:46:00 +03:00
parent 8c679a08c4
commit b4007038fb
3 changed files with 397 additions and 97 deletions

View file

@ -116,6 +116,7 @@ int main(int argc, char *argv[])
app.setQuitOnLastWindowClosed(false); app.setQuitOnLastWindowClosed(false);
qRegisterMetaType<VpnProtocol::ConnectionState>("VpnProtocol::ConnectionState");
qRegisterMetaType<DockerContainer>("DockerContainer"); qRegisterMetaType<DockerContainer>("DockerContainer");
qRegisterMetaType<TransportProto>("TransportProto"); qRegisterMetaType<TransportProto>("TransportProto");
qRegisterMetaType<Protocol>("Protocol"); qRegisterMetaType<Protocol>("Protocol");

View file

@ -1,14 +1,20 @@
#include <QCoreApplication> #include <QCoreApplication>
#include <QFileInfo> #include <QFileInfo>
#include <QProcess> #include <QProcess>
#include <QRegularExpression> //#include <QRegularExpression>
#include <QTcpSocket> //#include <QTcpSocket>
#include <QThread> #include <QThread>
#include <chrono>
#include "debug.h" #include "debug.h"
#include "ikev2_vpn_protocol.h" #include "ikev2_vpn_protocol.h"
#include "utils.h" #include "utils.h"
static std::atomic<RASCONNSTATE>_connection_state;
static std::mutex mtx;
static std::condition_variable cv;
static std::atomic_bool newEvent{false};
Ikev2Protocol::Ikev2Protocol(const QJsonObject &configuration, QObject* parent) : Ikev2Protocol::Ikev2Protocol(const QJsonObject &configuration, QObject* parent) :
VpnProtocol(configuration, parent) VpnProtocol(configuration, parent)
@ -20,30 +26,40 @@ Ikev2Protocol::Ikev2Protocol(const QJsonObject &configuration, QObject* parent)
Ikev2Protocol::~Ikev2Protocol() Ikev2Protocol::~Ikev2Protocol()
{ {
qDebug() << "IpsecProtocol::~IpsecProtocol()"; qDebug() << "IpsecProtocol::~IpsecProtocol()";
#ifdef Q_OS_WIN
_stoped.store(true);
disconnect_vpn();
#endif
Ikev2Protocol::stop(); Ikev2Protocol::stop();
QThread::msleep(200); QThread::msleep(200);
_th_conn_state->join();
_thr->join();
} }
void Ikev2Protocol::stop() void Ikev2Protocol::stop()
{ {
#ifdef Q_OS_WINDOWS #ifdef Q_OS_WINDOWS
{ {
setConnectionState(Disconnecting); _stoped.store(true);
//setConnectionState(Disconnecting);
auto disconnectProcess = new QProcess; //auto disconnectProcess = new QProcess;
disconnectProcess->setProgram("rasdial"); // disconnectProcess->setProgram("rasdial");
QString arguments = QString("\"%1\" /disconnect") // QString arguments = QString("\"%1\" /disconnect")
.arg(tunnelName()); // .arg(tunnelName());
disconnectProcess->setNativeArguments(arguments); // disconnectProcess->setNativeArguments(arguments);
// connect(connectProcess, &QProcess::readyRead, [connectProcess]() { // // connect(connectProcess, &QProcess::readyRead, [connectProcess]() {
// qDebug().noquote() << "connectProcess readyRead" << connectProcess->readAll(); // // qDebug().noquote() << "connectProcess readyRead" << connectProcess->readAll();
// }); // // });
disconnectProcess->start(); // disconnectProcess->start();
disconnectProcess->waitForFinished(5000); // disconnectProcess->waitForFinished(5000);
setConnectionState(Disconnected); // setConnectionState(Disconnected);
if (! disconnect_vpn() ){
qDebug()<<"We don't disconnect";
}
} }
#endif #endif
} }
@ -57,7 +73,7 @@ ErrorCode Ikev2Protocol::start()
{ {
#ifdef Q_OS_WINDOWS #ifdef Q_OS_WINDOWS
QByteArray cert = QByteArray::fromBase64(m_config[config_key::cert].toString().toUtf8()); QByteArray cert = QByteArray::fromBase64(m_config[config_key::cert].toString().toUtf8());
setConnectionState(ConnectionState::Connecting); setConnectionState(Connecting);
QTemporaryFile certFile; QTemporaryFile certFile;
certFile.setAutoRemove(false); certFile.setAutoRemove(false);
@ -65,7 +81,6 @@ ErrorCode Ikev2Protocol::start()
certFile.write(cert); certFile.write(cert);
certFile.close(); certFile.close();
{ {
auto certInstallProcess = IpcClient::CreatePrivilegedProcess(); auto certInstallProcess = IpcClient::CreatePrivilegedProcess();
@ -105,19 +120,30 @@ ErrorCode Ikev2Protocol::start()
certInstallProcess->start(); certInstallProcess->start();
} }
// /*
{ {
auto adapterRemoveProcess = new QProcess; // auto adapterRemoveProcess = new QProcess;
adapterRemoveProcess->setProgram("powershell"); // adapterRemoveProcess->setProgram("powershell");
QString arguments = QString("-command \"Remove-VpnConnection -Name '%1' -Force\"").arg(tunnelName()); // QString arguments = QString("-command \"Remove-VpnConnection -Name '%1' -Force\"").arg(tunnelName());
adapterRemoveProcess->setNativeArguments(arguments); // adapterRemoveProcess->setNativeArguments(arguments);
adapterRemoveProcess->start(); // adapterRemoveProcess->start();
adapterRemoveProcess->waitForFinished(5000); // 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; auto adapterInstallProcess = new QProcess;
adapterInstallProcess->setProgram("powershell"); adapterInstallProcess->setProgram("powershell");
@ -131,10 +157,6 @@ ErrorCode Ikev2Protocol::start()
.arg(m_config[config_key::hostName].toString()) .arg(m_config[config_key::hostName].toString())
.arg(tunnelName()); .arg(tunnelName());
adapterInstallProcess->setNativeArguments(arguments); adapterInstallProcess->setNativeArguments(arguments);
// connect(adapterInstallProcess, &QProcess::readyRead, [adapterInstallProcess]() {
// qDebug().noquote() << "adapterInstallProcess readyRead" << adapterInstallProcess->readAll();
// });
adapterInstallProcess->start(); adapterInstallProcess->start();
adapterInstallProcess->waitForFinished(5000); adapterInstallProcess->waitForFinished(5000);
} }
@ -162,57 +184,303 @@ ErrorCode Ikev2Protocol::start()
adapterConfigProcess->start(); adapterConfigProcess->start();
adapterConfigProcess->waitForFinished(5000); adapterConfigProcess->waitForFinished(5000);
} }
//*/
{ {
// char buf[RASBUFFER]= {0}; if (connect_to_vpn(tunnelName())){
// DWORD err = 0; _thr = std::make_unique<std::thread>(&Ikev2Protocol::_ikev2_states, this);
// RASDIALPARAMSA *param = (RASDIALPARAMSA *)buf; }else{
// param->dwSize = 1064; qDebug()<<"We can't connect to VPN";
// 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);
} }
}
setConnectionState(Connected); //setConnectionState(Connecting);
return ErrorCode::NoError;
#else
return ErrorCode::NoError; return ErrorCode::NoError;
#endif #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<LPRASENTRY>(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<std::thread>(&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<std::mutex> lck(mtx);
while ( !newEvent ){
cv.wait(lck);
}
qDebug()<<"Recive the new event "<<static_cast<int>(_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 #ifdef Q_OS_WINDOWS
DWORD CALLBACK rasCallback(UINT msg, RASCONNSTATE rascs, DWORD err) void WINAPI Ikev2Protocol::RasDialFuncCallback(UINT /*unMsg*/,
{ RASCONNSTATE rasconnstate,
if(err != 0) { DWORD dwError ){
printf("Error: %d\n", err);
fflush(stdout); qDebug() << "Ikev2Protocol::RasDialFuncCallback" << rasconnstate << dwError;
//g_done = 1; _connection_state = rasconnstate;
return 0; // stop the connection. newEvent = true;
} else { cv.notify_all();
//printf("%s\n", rasState(rascs));
fflush(stdout);
if(rascs == RASCS_Connected) {
printf("Success: Connected\n");
fflush(stdout);
//g_done = 1;
}
return 1;
}
} }
#endif #endif

View file

@ -11,20 +11,26 @@
#include "core/ipcclient.h" #include "core/ipcclient.h"
#ifdef Q_OS_WIN #ifdef Q_OS_WIN
#include <stdio.h> #include <string>
#include <stdlib.h> #include <memory>
#include <string.h> #include <atomic>
#include <thread>
#include <condition_variable>
#include <mutex>
#include <stdio.h>
#include <windows.h> #include <windows.h>
#include <ras.h> #include <Ras.h>
#include <raserror.h> #include <raserror.h>
#include <shlwapi.h> #include <shlwapi.h>
#include <wincrypt.h>
#pragma comment(lib, "shlwapi.lib") #pragma comment(lib, "shlwapi.lib")
#pragma comment(lib, "rasapi32.lib") #pragma comment(lib, "rasapi32.lib")
#pragma comment(lib, "Crypt32.lib")
#define RASBUFFER 0x1000
#define RASMAXENUM 0x100
#endif #endif
class Ikev2Protocol : public VpnProtocol class Ikev2Protocol : public VpnProtocol
@ -43,14 +49,39 @@ public:
private: private:
void readIkev2Configuration(const QJsonObject &configuration); void readIkev2Configuration(const QJsonObject &configuration);
#ifdef Q_OS_WIN
//certificates variables
#endif
private: private:
QJsonObject m_config; QJsonObject m_config;
#ifdef Q_OS_WIN #ifdef Q_OS_WIN
HRASCONN g_h; //RAS functions and parametrs
int g_done = 0; 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<std::thread> _thr{nullptr};
void _ikev2_states();
std::atomic_bool _stoped{false};
std::unique_ptr<std::thread>_th_conn_state{nullptr};
void conn_state();
signals:
//void Ikev2_connected();
//void Ikev2_disconnected();
//void Ikev2_state(int);
#endif #endif
}; };
#ifdef Q_OS_WIN #ifdef Q_OS_WIN