From c3fdd977b1aaa5d4c803530e5d6f41ef87b93645 Mon Sep 17 00:00:00 2001 From: Mykola Baibuz Date: Wed, 29 Nov 2023 22:50:36 +0200 Subject: [PATCH] Windows OpenVPN/OpenVPN+Cloak killswitch feature --- client/protocols/openvpnprotocol.cpp | 23 ++++++-- client/protocols/openvpnprotocol.h | 1 + ipc/ipc_interface.rep | 5 ++ ipc/ipcserver.cpp | 79 ++++++++++++++++++++++++++-- ipc/ipcserver.h | 5 ++ 5 files changed, 105 insertions(+), 8 deletions(-) diff --git a/client/protocols/openvpnprotocol.cpp b/client/protocols/openvpnprotocol.cpp index c38c6eea..c7cc839d 100644 --- a/client/protocols/openvpnprotocol.cpp +++ b/client/protocols/openvpnprotocol.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include "logger.h" #include "openvpnprotocol.h" @@ -53,6 +54,11 @@ void OpenVpnProtocol::stop() QThread::msleep(10); m_managementServer.stop(); } + +#ifdef Q_OS_WIN + IpcClient::Interface()->disableKillSwitch(); +#endif + setConnectionState(Vpn::ConnectionState::Disconnected); } @@ -85,13 +91,13 @@ void OpenVpnProtocol::killOpenVpnProcess() void OpenVpnProtocol::readOpenVpnConfiguration(const QJsonObject &configuration) { if (configuration.contains(ProtocolProps::key_proto_config_data(Proto::OpenVpn))) { + m_configData = configuration; QJsonObject jConfig = configuration.value(ProtocolProps::key_proto_config_data(Proto::OpenVpn)).toObject(); m_configFile.open(); m_configFile.write(jConfig.value(config_key::config).toString().toUtf8()); m_configFile.close(); m_configFileName = m_configFile.fileName(); - qDebug().noquote() << QString("Set config data") << m_configFileName; } } @@ -320,14 +326,25 @@ void OpenVpnProtocol::updateVpnGateway(const QString &line) // line looks like // PUSH: Received control message: 'PUSH_REPLY,route 10.8.0.1,topology net30,ping 10,ping-restart // 120,ifconfig 10.8.0.6 10.8.0.5,peer-id 0,cipher AES-256-GCM' - QStringList params = line.split(","); for (const QString &l : params) { if (l.contains("ifconfig")) { if (l.split(" ").size() == 3) { m_vpnLocalAddress = l.split(" ").at(1); m_vpnGateway = l.split(" ").at(2); - +#ifdef Q_OS_WIN + QList netInterfaces = QNetworkInterface::allInterfaces(); + for (int i = 0; i < netInterfaces.size(); i++) { + for (int j=0; j < netInterfaces.at(i).addressEntries().size(); j++) + { + if (m_vpnLocalAddress == netInterfaces.at(i).addressEntries().at(j).ip().toString()) { + IpcClient::Interface()->enableKillSwitch(netInterfaces.at(i).index()); + m_configData.insert("vpnGateway", m_vpnGateway); + IpcClient::Interface()->enablePeerTraffic(m_configData); + } + } + } +#endif qDebug() << QString("Set vpn local address %1, gw %2").arg(m_vpnLocalAddress).arg(vpnGateway()); } } diff --git a/client/protocols/openvpnprotocol.h b/client/protocols/openvpnprotocol.h index ad80fe50..b07d1268 100644 --- a/client/protocols/openvpnprotocol.h +++ b/client/protocols/openvpnprotocol.h @@ -44,6 +44,7 @@ private: ManagementServer m_managementServer; QString m_configFileName; + QJsonObject m_configData; QTemporaryFile m_configFile; uint selectMgmtPort(); diff --git a/ipc/ipc_interface.rep b/ipc/ipc_interface.rep index 8970f7c8..faf70079 100644 --- a/ipc/ipc_interface.rep +++ b/ipc/ipc_interface.rep @@ -1,5 +1,7 @@ #include #include +#include +#include "../client/daemon/interfaceconfig.h" class IpcInterface { @@ -22,5 +24,8 @@ class IpcInterface SLOT( bool copyWireguardConfig(const QString &sourcePath) ); SLOT( bool isWireguardRunning() ); SLOT( bool isWireguardConfigExists(const QString &configPath) ); + SLOT( bool enableKillSwitch(int vpnAdapterIndex) ); + SLOT( bool disableKillSwitch() ); + SLOT( bool enablePeerTraffic(const QJsonObject &configStr)); }; diff --git a/ipc/ipcserver.cpp b/ipc/ipcserver.cpp index e9f57c60..4517a5bf 100644 --- a/ipc/ipcserver.cpp +++ b/ipc/ipcserver.cpp @@ -8,8 +8,11 @@ #include "router.h" #include "logger.h" +#include "../client/protocols/protocols_defs.h" #ifdef Q_OS_WIN #include "tapcontroller_win.h" +#include "../client/platforms/windows/daemon/windowsfirewall.h" + #endif IpcServer::IpcServer(QObject *parent): @@ -22,15 +25,14 @@ int IpcServer::createPrivilegedProcess() qDebug() << "IpcServer::createPrivilegedProcess"; #endif +#ifdef Q_OS_WIN + WindowsFirewall::instance()->init(); +#endif + m_localpid++; ProcessDescriptor pd(this); -// pd.serverNode->setHostUrl(QUrl(amnezia::getIpcProcessUrl(m_localpid))); -// pd.serverNode->enableRemoting(pd.ipcProcess.data()); - - - //pd.localServer = QSharedPointer(new QLocalServer(this)); pd.localServer->setSocketOptions(QLocalServer::WorldAccessOption); if (!pd.localServer->listen(amnezia::getIpcProcessUrl(m_localpid))) { @@ -223,3 +225,70 @@ bool IpcServer::isWireguardConfigExists(const QString &configPath) return QFileInfo::exists(configPath); } + +bool IpcServer::enableKillSwitch(int vpnAdapterIndex) +{ +#ifdef Q_OS_WIN + return WindowsFirewall::instance()->enableKillSwitch(vpnAdapterIndex); +#endif + return true; +} + +bool IpcServer::disableKillSwitch() +{ +#ifdef Q_OS_WIN + return WindowsFirewall::instance()->disableKillSwitch(); +#endif + return true; +} + +bool IpcServer::enablePeerTraffic(const QJsonObject &configStr) +{ +#ifdef Q_OS_WIN + InterfaceConfig config; + config.m_dnsServer = configStr.value(amnezia::config_key::dns1).toString(); + config.m_serverPublicKey = "openvpn"; + config.m_serverIpv4Gateway = configStr.value("vpnGateway").toString(); + + int splitTunnelType = configStr.value("splitTunnelType").toInt(); + QJsonArray splitTunnelSites = configStr.value("splitTunnelSites").toArray(); + + qDebug() << "splitTunnelType " << splitTunnelType << "splitTunnelSites " << splitTunnelSites; + + QStringList AllowedIPAddesses; + + // Use APP split tunnel + if (splitTunnelType == 0 || splitTunnelType == 2) { + config.m_allowedIPAddressRanges.append( + IPAddress(QHostAddress("0.0.0.0"), 0)); + config.m_allowedIPAddressRanges.append( + IPAddress(QHostAddress("::"), 0)); + } + + if (splitTunnelType == 1) { + for (auto v : splitTunnelSites) { + QString ipRange = v.toString(); + qDebug() << "ipRange " << ipRange; + if (ipRange.split('/').size() > 1){ + config.m_allowedIPAddressRanges.append( + IPAddress(QHostAddress(ipRange.split('/')[0]), atoi(ipRange.split('/')[1].toLocal8Bit()))); + } else { + config.m_allowedIPAddressRanges.append( + IPAddress(QHostAddress(ipRange), 32)); + + } + } + } + + config.m_excludedAddresses.append(configStr.value(amnezia::config_key::hostName).toString()); + if (splitTunnelType == 2) { + for (auto v : splitTunnelSites) { + QString ipRange = v.toString(); + config.m_excludedAddresses.append(ipRange); + } + } + + return WindowsFirewall::instance()->enablePeerTraffic(config); +#endif + return true; +} diff --git a/ipc/ipcserver.h b/ipc/ipcserver.h index d5706784..1508049a 100644 --- a/ipc/ipcserver.h +++ b/ipc/ipcserver.h @@ -4,6 +4,8 @@ #include #include #include +#include +#include "../client/daemon/interfaceconfig.h" #include "ipc.h" #include "ipcserverprocess.h" @@ -28,6 +30,9 @@ public: virtual bool copyWireguardConfig(const QString &sourcePath) override; virtual bool isWireguardRunning() override; virtual bool isWireguardConfigExists(const QString &configPath) override; + virtual bool enableKillSwitch(int vpnAdapterIndex) override; + virtual bool disableKillSwitch() override; + virtual bool enablePeerTraffic(const QJsonObject &configStr) override; private: int m_localpid = 0;