Compare commits
26 commits
dev
...
feature/ma
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1192f3d8a7 | ||
|
|
afd2542a11 | ||
|
|
5961d4cefc | ||
|
|
1438a21902 | ||
|
|
f72684e4d4 | ||
|
|
898f497f8e | ||
|
|
8c94f70edf | ||
|
|
a144d495ee | ||
|
|
f0e66e4ecf | ||
|
|
6f0e9a136b | ||
|
|
4147632a62 | ||
|
|
948ab4cf71 | ||
|
|
f54308e4f4 | ||
|
|
052261c2b4 | ||
|
|
3cec0dc2a7 | ||
|
|
ad61ef0b22 | ||
|
|
63c569c3d2 | ||
|
|
30df4c6800 | ||
|
|
a96f9dc18a | ||
|
|
fb63cdf7e9 | ||
|
|
2d3b9c2752 | ||
|
|
09c58cb39e | ||
|
|
654d219e7e | ||
|
|
89d4c18e87 | ||
|
|
b0b185027e | ||
|
|
90912f9231 |
24 changed files with 1116 additions and 25 deletions
|
|
@ -317,6 +317,15 @@ endif()
|
||||||
if(LINUX AND NOT ANDROID)
|
if(LINUX AND NOT ANDROID)
|
||||||
set(LIBS ${LIBS} -static-libstdc++ -static-libgcc -ldl)
|
set(LIBS ${LIBS} -static-libstdc++ -static-libgcc -ldl)
|
||||||
link_directories(${CMAKE_CURRENT_LIST_DIR}/platforms/linux)
|
link_directories(${CMAKE_CURRENT_LIST_DIR}/platforms/linux)
|
||||||
|
|
||||||
|
set(HEADERS ${HEADERS}
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/protocols/ikev2_vpn_protocol_linux.h
|
||||||
|
)
|
||||||
|
|
||||||
|
set(SOURCES ${SOURCES}
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/protocols/ikev2_vpn_protocol_linux.cpp
|
||||||
|
)
|
||||||
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(WIN32 OR (APPLE AND NOT IOS) OR (LINUX AND NOT ANDROID))
|
if(WIN32 OR (APPLE AND NOT IOS) OR (LINUX AND NOT ANDROID))
|
||||||
|
|
|
||||||
|
|
@ -18,17 +18,22 @@ set(LIBS ${LIBS}
|
||||||
${FW_NETWORK_EXTENSION}
|
${FW_NETWORK_EXTENSION}
|
||||||
)
|
)
|
||||||
|
|
||||||
set_target_properties(${PROJECT} PROPERTIES MACOSX_BUNDLE TRUE)
|
set_target_properties(${PROJECT} PROPERTIES
|
||||||
|
MACOSX_BUNDLE TRUE
|
||||||
|
XCODE_ATTRIBUTE_CODE_SIGN_ENTITLEMENTS "${CMAKE_CURRENT_SOURCE_DIR}/macos/app/AmneziaVPN.entitlements"
|
||||||
|
)
|
||||||
set(CMAKE_OSX_ARCHITECTURES "x86_64" CACHE INTERNAL "" FORCE)
|
set(CMAKE_OSX_ARCHITECTURES "x86_64" CACHE INTERNAL "" FORCE)
|
||||||
set(CMAKE_OSX_DEPLOYMENT_TARGET 10.15)
|
set(CMAKE_OSX_DEPLOYMENT_TARGET 10.15)
|
||||||
|
|
||||||
|
|
||||||
set(HEADERS ${HEADERS}
|
set(HEADERS ${HEADERS}
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/ui/macos_util.h
|
${CMAKE_CURRENT_SOURCE_DIR}/ui/macos_util.h
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/protocols/ikev2_vpn_protocol_mac.h
|
||||||
)
|
)
|
||||||
|
|
||||||
set(SOURCES ${SOURCES}
|
set(SOURCES ${SOURCES}
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/ui/macos_util.mm
|
${CMAKE_CURRENT_SOURCE_DIR}/ui/macos_util.mm
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/protocols/ikev2_vpn_protocol_mac.mm
|
||||||
)
|
)
|
||||||
|
|
||||||
set(ICON_FILE ${CMAKE_CURRENT_SOURCE_DIR}/images/app.icns)
|
set(ICON_FILE ${CMAKE_CURRENT_SOURCE_DIR}/images/app.icns)
|
||||||
|
|
|
||||||
|
|
@ -64,6 +64,26 @@ QString Ikev2Configurator::createConfig(const ServerCredentials &credentials, Do
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(Q_OS_LINUX)
|
||||||
|
QString config = m_serverController->replaceVars(amnezia::scriptData(ProtocolScriptType::ipsec_template, container),
|
||||||
|
m_serverController->genVarsForScript(credentials, container, containerConfig));
|
||||||
|
|
||||||
|
config.replace("$CLIENT_NAME", connData.clientId);
|
||||||
|
config.replace("$UUID1", QUuid::createUuid().toString());
|
||||||
|
config.replace("$SERVER_ADDR", connData.host);
|
||||||
|
|
||||||
|
QJsonObject jConfig;
|
||||||
|
jConfig[config_key::config] = config;
|
||||||
|
|
||||||
|
jConfig[config_key::hostName] = connData.host;
|
||||||
|
jConfig[config_key::userName] = connData.clientId;
|
||||||
|
jConfig[config_key::cert] = QString(connData.clientCert.toBase64());
|
||||||
|
jConfig[config_key::cacert] = QString(connData.caCert);
|
||||||
|
jConfig[config_key::password] = connData.password;
|
||||||
|
|
||||||
|
return QJsonDocument(jConfig).toJson();
|
||||||
|
#endif
|
||||||
|
|
||||||
return genIkev2Config(connData);
|
return genIkev2Config(connData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -73,6 +93,7 @@ QString Ikev2Configurator::genIkev2Config(const ConnectionData &connData)
|
||||||
config[config_key::hostName] = connData.host;
|
config[config_key::hostName] = connData.host;
|
||||||
config[config_key::userName] = connData.clientId;
|
config[config_key::userName] = connData.clientId;
|
||||||
config[config_key::cert] = QString(connData.clientCert.toBase64());
|
config[config_key::cert] = QString(connData.clientCert.toBase64());
|
||||||
|
config[config_key::cacert] = QString(connData.caCert);
|
||||||
config[config_key::password] = connData.password;
|
config[config_key::password] = connData.password;
|
||||||
|
|
||||||
return QJsonDocument(config).toJson();
|
return QJsonDocument(config).toJson();
|
||||||
|
|
@ -115,3 +136,22 @@ QString Ikev2Configurator::genStrongSwanConfig(const ConnectionData &connData)
|
||||||
|
|
||||||
return config;
|
return config;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString Ikev2Configurator::processConfigWithLocalSettings(const QPair<QString, QString> &dns, const bool isApiConfig,
|
||||||
|
QString &protocolConfigString)
|
||||||
|
{
|
||||||
|
processConfigWithDnsSettings(dns, protocolConfigString);
|
||||||
|
|
||||||
|
QJsonObject json;
|
||||||
|
json[config_key::config] = protocolConfigString;
|
||||||
|
return QJsonDocument(json).toJson();
|
||||||
|
}
|
||||||
|
|
||||||
|
QString Ikev2Configurator::processConfigWithExportSettings(const QPair<QString, QString> &dns, const bool isApiConfig,
|
||||||
|
QString &protocolConfigString)
|
||||||
|
{
|
||||||
|
processConfigWithDnsSettings(dns, protocolConfigString);
|
||||||
|
QJsonObject json;
|
||||||
|
json[config_key::config] = protocolConfigString;
|
||||||
|
return QJsonDocument(json).toJson();
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,10 @@ public:
|
||||||
QString genIkev2Config(const ConnectionData &connData);
|
QString genIkev2Config(const ConnectionData &connData);
|
||||||
QString genMobileConfig(const ConnectionData &connData);
|
QString genMobileConfig(const ConnectionData &connData);
|
||||||
QString genStrongSwanConfig(const ConnectionData &connData);
|
QString genStrongSwanConfig(const ConnectionData &connData);
|
||||||
|
QString genIPSecConfig(const ConnectionData &connData);
|
||||||
|
|
||||||
|
QString processConfigWithLocalSettings(const QPair<QString, QString> &dns, const bool isApiConfig, QString &protocolConfigString);
|
||||||
|
QString processConfigWithExportSettings(const QPair<QString, QString> &dns, const bool isApiConfig, QString &protocolConfigString);
|
||||||
|
|
||||||
ConnectionData prepareIkev2Config(const ServerCredentials &credentials,
|
ConnectionData prepareIkev2Config(const ServerCredentials &credentials,
|
||||||
DockerContainer container, ErrorCode &errorCode);
|
DockerContainer container, ErrorCode &errorCode);
|
||||||
|
|
|
||||||
|
|
@ -277,7 +277,7 @@ Proto ContainerProps::defaultProtocol(DockerContainer c)
|
||||||
|
|
||||||
bool ContainerProps::isSupportedByCurrentPlatform(DockerContainer c)
|
bool ContainerProps::isSupportedByCurrentPlatform(DockerContainer c)
|
||||||
{
|
{
|
||||||
#ifdef Q_OS_WINDOWS
|
#if defined(Q_OS_WINDOWS) || defined(Q_OS_LINUX)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
#elif defined(Q_OS_IOS)
|
#elif defined(Q_OS_IOS)
|
||||||
|
|
@ -294,7 +294,7 @@ bool ContainerProps::isSupportedByCurrentPlatform(DockerContainer c)
|
||||||
#elif defined(Q_OS_MAC)
|
#elif defined(Q_OS_MAC)
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case DockerContainer::WireGuard: return true;
|
case DockerContainer::WireGuard: return true;
|
||||||
case DockerContainer::Ipsec: return false;
|
case DockerContainer::Ipsec: return true;
|
||||||
default: return true;
|
default: return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -309,13 +309,6 @@ bool ContainerProps::isSupportedByCurrentPlatform(DockerContainer c)
|
||||||
case DockerContainer::SSXray: return true;
|
case DockerContainer::SSXray: return true;
|
||||||
default: return false;
|
default: return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
#elif defined(Q_OS_LINUX)
|
|
||||||
switch (c) {
|
|
||||||
case DockerContainer::Ipsec: return false;
|
|
||||||
default: return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
#else
|
#else
|
||||||
return false;
|
return false;
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,13 @@
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
#include <net/route.h>
|
#include <net/route.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <ifaddrs.h>
|
||||||
|
#include <libproc.h>
|
||||||
|
#include <netdb.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <semaphore.h>
|
||||||
|
#include <unistd.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <QHostAddress>
|
#include <QHostAddress>
|
||||||
|
|
@ -463,3 +470,112 @@ QString NetworkUtilities::getGatewayAndIface()
|
||||||
return gateway;
|
return gateway;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(Q_OS_MAC)
|
||||||
|
QString NetworkUtilities::ipAddressByInterfaceName(const QString &interfaceName)
|
||||||
|
{
|
||||||
|
struct ifaddrs *ifaddr, *ifa;
|
||||||
|
char host[NI_MAXHOST];
|
||||||
|
|
||||||
|
if (getifaddrs(&ifaddr) == -1)
|
||||||
|
{
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next)
|
||||||
|
{
|
||||||
|
if (ifa->ifa_addr == NULL)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
int family = ifa->ifa_addr->sa_family;
|
||||||
|
QString iname = QString::fromStdString(ifa->ifa_name);
|
||||||
|
|
||||||
|
if (family == AF_INET && iname == interfaceName)
|
||||||
|
{
|
||||||
|
int s = getnameinfo(ifa->ifa_addr,
|
||||||
|
(family == AF_INET) ? sizeof(struct sockaddr_in) :
|
||||||
|
sizeof(struct sockaddr_in6),
|
||||||
|
host, NI_MAXHOST,
|
||||||
|
NULL, 0, NI_NUMERICHOST);
|
||||||
|
if (s != 0)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
return QString::fromStdString(host);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
freeifaddrs(ifaddr);
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
QString NetworkUtilities::lastConnectedNetworkInterfaceName()
|
||||||
|
{
|
||||||
|
QString ifname("");
|
||||||
|
|
||||||
|
struct ifaddrs * interfaces = NULL;
|
||||||
|
struct ifaddrs * temp_addr = NULL;
|
||||||
|
|
||||||
|
if( getifaddrs(&interfaces) == 0 )
|
||||||
|
{
|
||||||
|
//Loop through linked list of interfaces
|
||||||
|
temp_addr = interfaces;
|
||||||
|
while( temp_addr != NULL )
|
||||||
|
{
|
||||||
|
if( temp_addr->ifa_addr->sa_family == AF_INET )
|
||||||
|
{
|
||||||
|
QString tname = temp_addr->ifa_name;
|
||||||
|
if( tname.startsWith("utun") )
|
||||||
|
ifname = tname;
|
||||||
|
else if( tname.startsWith("ipsec") )
|
||||||
|
ifname = tname;
|
||||||
|
else if( tname.startsWith("ppp") )
|
||||||
|
ifname = tname;
|
||||||
|
}
|
||||||
|
|
||||||
|
temp_addr = temp_addr->ifa_next;
|
||||||
|
}
|
||||||
|
|
||||||
|
freeifaddrs(interfaces);
|
||||||
|
}
|
||||||
|
return ifname;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString execCmd(const QString &cmd)
|
||||||
|
{
|
||||||
|
char buffer[1024];
|
||||||
|
QString result = "";
|
||||||
|
FILE* pipe = popen(cmd.toStdString().c_str(), "r");
|
||||||
|
if (!pipe) return "";
|
||||||
|
while (!feof(pipe))
|
||||||
|
{
|
||||||
|
if (fgets(buffer, 1024, pipe) != NULL)
|
||||||
|
{
|
||||||
|
result += buffer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pclose(pipe);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
QStringList NetworkUtilities::getListOfDnsNetworkServiceEntries()
|
||||||
|
{
|
||||||
|
QStringList result;
|
||||||
|
QString command = "echo 'list' | scutil | grep /Network/Service | grep DNS";
|
||||||
|
QString cmdOutput = execCmd(command).trimmed();
|
||||||
|
// qDebug() << "Raw result: " << cmdOutput;
|
||||||
|
|
||||||
|
QStringList lines = cmdOutput.split('\n');
|
||||||
|
for (QString line : lines)
|
||||||
|
{
|
||||||
|
if (line.contains("="))
|
||||||
|
{
|
||||||
|
QString entry = line.mid(line.indexOf("=")+1).trimmed();
|
||||||
|
result.append(entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,11 @@ public:
|
||||||
|
|
||||||
static QStringList summarizeRoutes(const QStringList &ips, const QString cidr);
|
static QStringList summarizeRoutes(const QStringList &ips, const QString cidr);
|
||||||
|
|
||||||
|
#if defined(Q_OS_MAC)
|
||||||
|
static QString ipAddressByInterfaceName(const QString &interfaceName);
|
||||||
|
static QString lastConnectedNetworkInterfaceName();
|
||||||
|
static QStringList getListOfDnsNetworkServiceEntries();
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // NETWORKUTILITIES_H
|
#endif // NETWORKUTILITIES_H
|
||||||
|
|
|
||||||
|
|
@ -50,6 +50,7 @@ QString amnezia::scriptName(ProtocolScriptType type)
|
||||||
case ProtocolScriptType::wireguard_template: return QLatin1String("template.conf");
|
case ProtocolScriptType::wireguard_template: return QLatin1String("template.conf");
|
||||||
case ProtocolScriptType::awg_template: return QLatin1String("template.conf");
|
case ProtocolScriptType::awg_template: return QLatin1String("template.conf");
|
||||||
case ProtocolScriptType::xray_template: return QLatin1String("template.json");
|
case ProtocolScriptType::xray_template: return QLatin1String("template.json");
|
||||||
|
case ProtocolScriptType::ipsec_template: return QLatin1String("template.conf");
|
||||||
default: return QString();
|
default: return QString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,8 @@ enum ProtocolScriptType {
|
||||||
openvpn_template,
|
openvpn_template,
|
||||||
wireguard_template,
|
wireguard_template,
|
||||||
awg_template,
|
awg_template,
|
||||||
xray_template
|
xray_template,
|
||||||
|
ipsec_template
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
14
client/macos/app/AmneziaVPN.entitlements
Normal file
14
client/macos/app/AmneziaVPN.entitlements
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>com.apple.developer.networking.networkextension</key>
|
||||||
|
<array>
|
||||||
|
<string>packet-tunnel-provider</string>
|
||||||
|
</array>
|
||||||
|
<key>com.apple.developer.networking.vpn.api</key>
|
||||||
|
<array>
|
||||||
|
<string>allow-vpn</string>
|
||||||
|
</array>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
159
client/protocols/ikev2_vpn_protocol_linux.cpp
Normal file
159
client/protocols/ikev2_vpn_protocol_linux.cpp
Normal file
|
|
@ -0,0 +1,159 @@
|
||||||
|
#include <QCoreApplication>
|
||||||
|
#include <QFileInfo>
|
||||||
|
#include <QProcess>
|
||||||
|
|
||||||
|
#include <QThread>
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
|
|
||||||
|
#include "core/networkUtilities.h"
|
||||||
|
|
||||||
|
#include "logger.h"
|
||||||
|
#include "ikev2_vpn_protocol_linux.h"
|
||||||
|
#include "utilities.h"
|
||||||
|
#include "core/ipcclient.h"
|
||||||
|
#include <openssl/pkcs12.h>
|
||||||
|
#include <openssl/bio.h>
|
||||||
|
#include <openssl/pem.h>
|
||||||
|
|
||||||
|
|
||||||
|
static Ikev2Protocol* self = nullptr;
|
||||||
|
|
||||||
|
|
||||||
|
Ikev2Protocol::Ikev2Protocol(const QJsonObject &configuration, QObject* parent) :
|
||||||
|
VpnProtocol(configuration, parent)
|
||||||
|
{
|
||||||
|
self = this;
|
||||||
|
readIkev2Configuration(configuration);
|
||||||
|
m_routeGateway = NetworkUtilities::getGatewayAndIface();
|
||||||
|
m_vpnGateway = "192.168.43.10";
|
||||||
|
m_vpnLocalAddress = "192.168.43.10";
|
||||||
|
m_remoteAddress = configuration.value(amnezia::config_key::hostName).toString();
|
||||||
|
m_routeMode = configuration.value(amnezia::config_key::splitTunnelType).toInt();
|
||||||
|
}
|
||||||
|
|
||||||
|
Ikev2Protocol::~Ikev2Protocol()
|
||||||
|
{
|
||||||
|
qDebug() << "IpsecProtocol::~IpsecProtocol()";
|
||||||
|
Ikev2Protocol::stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Ikev2Protocol::stop()
|
||||||
|
{
|
||||||
|
setConnectionState(Vpn::ConnectionState::Disconnected);
|
||||||
|
Ikev2Protocol::disconnect_vpn();
|
||||||
|
qDebug() << "IpsecProtocol::stop()";
|
||||||
|
}
|
||||||
|
|
||||||
|
void Ikev2Protocol::readIkev2Configuration(const QJsonObject &configuration)
|
||||||
|
{
|
||||||
|
QJsonObject ikev2_data = configuration.value(ProtocolProps::key_proto_config_data(Proto::Ikev2)).toObject();
|
||||||
|
m_config = QJsonDocument::fromJson(ikev2_data.value(config_key::config).toString().toUtf8()).object();
|
||||||
|
}
|
||||||
|
|
||||||
|
ErrorCode Ikev2Protocol::start()
|
||||||
|
{
|
||||||
|
STACK_OF(X509) *certstack = sk_X509_new_null();
|
||||||
|
BIO *p12 = BIO_new(BIO_s_mem());
|
||||||
|
|
||||||
|
EVP_PKEY *pkey;
|
||||||
|
X509 *cert;
|
||||||
|
|
||||||
|
BIO_write(p12, QByteArray::fromBase64(m_config[config_key::cert].toString().toUtf8()),
|
||||||
|
QByteArray::fromBase64(m_config[config_key::cert].toString().toUtf8()).size());
|
||||||
|
|
||||||
|
PKCS12 *pkcs12 = d2i_PKCS12_bio(p12, NULL);
|
||||||
|
PKCS12_parse(pkcs12, m_config[config_key::password].toString().toStdString().c_str(), &pkey, &cert, &certstack);
|
||||||
|
BIO *bio = BIO_new(BIO_s_mem());
|
||||||
|
PEM_write_bio_X509(bio, cert);
|
||||||
|
|
||||||
|
BUF_MEM *mem = NULL;
|
||||||
|
BIO_get_mem_ptr(bio, &mem);
|
||||||
|
|
||||||
|
std::string pem(mem->data, mem->length);
|
||||||
|
QString alias(pem.c_str());
|
||||||
|
|
||||||
|
IpcClient::Interface()->writeIPsecUserCert(alias, m_config[config_key::userName].toString());
|
||||||
|
IpcClient::Interface()->writeIPsecConfig(m_config[config_key::config].toString());
|
||||||
|
IpcClient::Interface()->writeIPsecCaCert(m_config[config_key::cacert].toString(), m_config[config_key::userName].toString());
|
||||||
|
IpcClient::Interface()->writeIPsecPrivate(m_config[config_key::cert].toString(), m_config[config_key::userName].toString());
|
||||||
|
IpcClient::Interface()->writeIPsecPrivatePass(m_config[config_key::password].toString(), m_config[config_key::hostName].toString(),
|
||||||
|
m_config[config_key::userName].toString());
|
||||||
|
|
||||||
|
connect_to_vpn("ikev2-vpn");
|
||||||
|
|
||||||
|
if (!IpcClient::Interface()) {
|
||||||
|
return ErrorCode::AmneziaServiceConnectionFailed;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString connectionStatus;
|
||||||
|
|
||||||
|
auto futureResult = IpcClient::Interface()->getTunnelStatus("ikev2-vpn");
|
||||||
|
futureResult.waitForFinished();
|
||||||
|
|
||||||
|
if (futureResult.returnValue().isEmpty()) {
|
||||||
|
auto futureResult = IpcClient::Interface()->getTunnelStatus("ikev2-vpn");
|
||||||
|
futureResult.waitForFinished();
|
||||||
|
}
|
||||||
|
|
||||||
|
connectionStatus = futureResult.returnValue();
|
||||||
|
|
||||||
|
if (connectionStatus.contains("ESTABLISHED")) {
|
||||||
|
QStringList lines = connectionStatus.split('\n');
|
||||||
|
for (auto iter = lines.begin(); iter!=lines.end(); iter++)
|
||||||
|
{
|
||||||
|
if (iter->contains("0.0.0.0/0")) {
|
||||||
|
|
||||||
|
m_routeGateway = iter->split("===", Qt::SkipEmptyParts).first();
|
||||||
|
m_routeGateway = m_routeGateway.split(" ").at(2);
|
||||||
|
m_routeGateway = m_routeGateway.split("/").first();
|
||||||
|
m_vpnLocalAddress = m_routeGateway;
|
||||||
|
qDebug() << "m_routeGateway " << m_routeGateway;
|
||||||
|
|
||||||
|
|
||||||
|
// killSwitch toggle
|
||||||
|
if (QVariant(m_config.value(config_key::killSwitchOption).toString()).toBool()) {
|
||||||
|
IpcClient::Interface()->enableKillSwitch(m_config, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_routeMode == 0) {
|
||||||
|
IpcClient::Interface()->routeAddList(m_vpnGateway, QStringList() << "0.0.0.0/1");
|
||||||
|
IpcClient::Interface()->routeAddList(m_vpnGateway, QStringList() << "128.0.0.0/1");
|
||||||
|
IpcClient::Interface()->routeAddList(m_routeGateway, QStringList() << m_remoteAddress);
|
||||||
|
}
|
||||||
|
|
||||||
|
IpcClient::Interface()->StopRoutingIpv6();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setConnectionState(Vpn::ConnectionState::Connected);
|
||||||
|
} else {
|
||||||
|
setConnectionState(Vpn::ConnectionState::Disconnected);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ErrorCode::NoError;
|
||||||
|
}
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
bool Ikev2Protocol::create_new_vpn(const QString & vpn_name,
|
||||||
|
const QString & serv_addr) {
|
||||||
|
qDebug() << "Ikev2Protocol::create_new_vpn()";
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
bool Ikev2Protocol::delete_vpn_connection(const QString &vpn_name) {
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
bool Ikev2Protocol::connect_to_vpn(const QString &vpn_name) {
|
||||||
|
IpcClient::Interface()->startIPsec(vpn_name);
|
||||||
|
QThread::msleep(3000);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
bool Ikev2Protocol::disconnect_vpn() {
|
||||||
|
IpcClient::Interface()->stopIPsec("ikev2-vpn");
|
||||||
|
IpcClient::Interface()->disableKillSwitch();
|
||||||
|
IpcClient::Interface()->StartRoutingIpv6();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
51
client/protocols/ikev2_vpn_protocol_linux.h
Normal file
51
client/protocols/ikev2_vpn_protocol_linux.h
Normal file
|
|
@ -0,0 +1,51 @@
|
||||||
|
#ifndef IKEV2_VPN_PROTOCOL_LINUX_H
|
||||||
|
#define IKEV2_VPN_PROTOCOL_LINUX_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QProcess>
|
||||||
|
#include <QString>
|
||||||
|
#include <QTemporaryFile>
|
||||||
|
#include <QTimer>
|
||||||
|
|
||||||
|
#include "vpnprotocol.h"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <memory>
|
||||||
|
#include <atomic>
|
||||||
|
#include <thread>
|
||||||
|
#include <condition_variable>
|
||||||
|
#include <mutex>
|
||||||
|
|
||||||
|
class Ikev2Protocol : public VpnProtocol
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit Ikev2Protocol(const QJsonObject& configuration, QObject* parent = nullptr);
|
||||||
|
virtual ~Ikev2Protocol() override;
|
||||||
|
|
||||||
|
ErrorCode start() override;
|
||||||
|
void stop() override;
|
||||||
|
|
||||||
|
static QString tunnelName() { return "AmneziaVPN IKEv2"; }
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
void readIkev2Configuration(const QJsonObject &configuration);
|
||||||
|
|
||||||
|
private:
|
||||||
|
QJsonObject m_config;
|
||||||
|
QString m_remoteAddress;
|
||||||
|
int m_routeMode;
|
||||||
|
|
||||||
|
|
||||||
|
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();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // IKEV2_VPN_PROTOCOL_LINUX_H
|
||||||
45
client/protocols/ikev2_vpn_protocol_mac.h
Normal file
45
client/protocols/ikev2_vpn_protocol_mac.h
Normal file
|
|
@ -0,0 +1,45 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QTimer>
|
||||||
|
|
||||||
|
|
||||||
|
#include "openvpnprotocol.h"
|
||||||
|
|
||||||
|
|
||||||
|
class Ikev2Protocol : public VpnProtocol
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit Ikev2Protocol(const QJsonObject& configuration, QObject* parent = nullptr);
|
||||||
|
virtual ~Ikev2Protocol() override;
|
||||||
|
|
||||||
|
void readIkev2Configuration(const QJsonObject &configuration);
|
||||||
|
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();
|
||||||
|
void closeWindscribeActiveConnection();
|
||||||
|
ErrorCode start() override;
|
||||||
|
void stop() override;
|
||||||
|
|
||||||
|
static QString tunnelName() { return "AmneziaVPN IKEv2"; }
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void handleNotificationImpl(int status);
|
||||||
|
|
||||||
|
private:
|
||||||
|
mutable QRecursiveMutex mutex_;
|
||||||
|
void *notificationId_;
|
||||||
|
QJsonObject m_config;
|
||||||
|
QJsonObject m_ikev2_config;
|
||||||
|
|
||||||
|
QString ipsecAdapterName_;
|
||||||
|
|
||||||
|
bool isConnectingStateReachedAfterStartingConnection_;
|
||||||
|
|
||||||
|
void handleNotification(void *notification);
|
||||||
|
bool isFailedAuthError(QMap<time_t, QString> &logs);
|
||||||
|
bool isSocketError(QMap<time_t, QString> &logs);
|
||||||
|
bool setCustomDns(const QString &overrideDnsIpAddress);
|
||||||
|
};
|
||||||
397
client/protocols/ikev2_vpn_protocol_mac.mm
Normal file
397
client/protocols/ikev2_vpn_protocol_mac.mm
Normal file
|
|
@ -0,0 +1,397 @@
|
||||||
|
#include "ikev2_vpn_protocol_mac.h"
|
||||||
|
|
||||||
|
#include <core/networkUtilities.h>
|
||||||
|
#include <SystemConfiguration/SCSchemaDefinitions.h>
|
||||||
|
#include <SystemConfiguration/SCNetwork.h>
|
||||||
|
#include <SystemConfiguration/SCNetworkConnection.h>
|
||||||
|
#include <SystemConfiguration/SCNetworkConfiguration.h>
|
||||||
|
#import <NetworkExtension/NetworkExtension.h>
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
#include <QWaitCondition>
|
||||||
|
|
||||||
|
#include <openssl/bio.h>
|
||||||
|
#include <openssl/pkcs12.h>
|
||||||
|
#include <openssl/pem.h>
|
||||||
|
#include <openssl/err.h>
|
||||||
|
|
||||||
|
#include <sys/sysctl.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <net/if.h>
|
||||||
|
#include <net/route.h>
|
||||||
|
|
||||||
|
static NSString * const IKEv2ServiceName = @"AmneziaVPN IKEv2";
|
||||||
|
|
||||||
|
static Ikev2Protocol* self = nullptr;
|
||||||
|
|
||||||
|
Ikev2Protocol::Ikev2Protocol(const QJsonObject &configuration, QObject* parent) :
|
||||||
|
VpnProtocol(configuration, parent)
|
||||||
|
{
|
||||||
|
qDebug() << "IpsecProtocol::IpsecProtocol()";
|
||||||
|
m_routeGateway = NetworkUtilities::getGatewayAndIface();
|
||||||
|
self = this;
|
||||||
|
readIkev2Configuration(configuration);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ikev2Protocol::~Ikev2Protocol()
|
||||||
|
{
|
||||||
|
qDebug() << "IpsecProtocol::~IpsecProtocol()";
|
||||||
|
disconnect_vpn();
|
||||||
|
QThread::msleep(1000);
|
||||||
|
Ikev2Protocol::stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Ikev2Protocol::stop()
|
||||||
|
{
|
||||||
|
setConnectionState(Vpn::ConnectionState::Disconnected);
|
||||||
|
qDebug() << "IpsecProtocol::stop()";
|
||||||
|
}
|
||||||
|
|
||||||
|
void Ikev2Protocol::readIkev2Configuration(const QJsonObject &configuration)
|
||||||
|
{
|
||||||
|
qDebug() << "IpsecProtocol::readIkev2Configuration";
|
||||||
|
m_config = configuration;
|
||||||
|
auto ikev2_data = m_config.value(ProtocolProps::key_proto_config_data(Proto::Ikev2)).toObject();
|
||||||
|
m_ikev2_config = QJsonDocument::fromJson(ikev2_data.value(config_key::config).toString().toUtf8()).object();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
CFDataRef CreatePersistentRefForIdentity(SecIdentityRef identity)
|
||||||
|
{
|
||||||
|
CFTypeRef persistent_ref = NULL;
|
||||||
|
const void *keys[] = { kSecReturnPersistentRef, kSecValueRef };
|
||||||
|
const void *values[] = { kCFBooleanTrue, identity };
|
||||||
|
CFDictionaryRef dict = CFDictionaryCreate(NULL, keys, values,
|
||||||
|
sizeof(keys) / sizeof(*keys), NULL, NULL);
|
||||||
|
|
||||||
|
if (SecItemCopyMatching(dict, &persistent_ref) != 0) {
|
||||||
|
SecItemAdd(dict, &persistent_ref);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dict)
|
||||||
|
CFRelease(dict);
|
||||||
|
|
||||||
|
return (CFDataRef)persistent_ref;
|
||||||
|
}
|
||||||
|
|
||||||
|
NSData *searchKeychainCopyMatching(const char *certName)
|
||||||
|
{
|
||||||
|
NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
|
||||||
|
[dict setObject:(__bridge id)kSecClassCertificate forKey:(__bridge id)kSecClass];
|
||||||
|
[dict setObject:[NSString stringWithUTF8String:certName] forKey:(__bridge id)kSecAttrLabel];
|
||||||
|
[dict setObject:(__bridge id)kSecMatchLimitOne forKey:(__bridge id)kSecMatchLimit];
|
||||||
|
[dict setObject:@YES forKey:(__bridge id)kSecReturnPersistentRef];
|
||||||
|
|
||||||
|
CFTypeRef result = NULL;
|
||||||
|
SecItemCopyMatching((__bridge CFDictionaryRef)dict, &result);
|
||||||
|
|
||||||
|
return (NSData *)result;
|
||||||
|
}
|
||||||
|
|
||||||
|
ErrorCode Ikev2Protocol::start()
|
||||||
|
{
|
||||||
|
|
||||||
|
qDebug() << "IpsecProtocol::start";
|
||||||
|
|
||||||
|
static QMutex mutexLocal;
|
||||||
|
mutexLocal.lock();
|
||||||
|
|
||||||
|
setConnectionState(Vpn::ConnectionState::Disconnected);
|
||||||
|
NEVPNManager *manager = [NEVPNManager sharedManager];
|
||||||
|
|
||||||
|
[manager loadFromPreferencesWithCompletionHandler:^(NSError *err)
|
||||||
|
{
|
||||||
|
mutexLocal.lock();
|
||||||
|
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
qDebug() << "First load vpn preferences failed:" << QString::fromNSString(err.localizedDescription);
|
||||||
|
setConnectionState(Vpn::ConnectionState::Disconnected);
|
||||||
|
mutexLocal.unlock();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
|
||||||
|
NSData *output = NULL;
|
||||||
|
|
||||||
|
BIO *ibio, *obio = NULL;
|
||||||
|
BUF_MEM *bptr;
|
||||||
|
|
||||||
|
STACK_OF(X509) *certstack = sk_X509_new_null();
|
||||||
|
BIO *p12 = BIO_new(BIO_s_mem());
|
||||||
|
|
||||||
|
EVP_PKEY *pkey;
|
||||||
|
X509 *cert;
|
||||||
|
|
||||||
|
BIO_write(p12, QByteArray::fromBase64(m_ikev2_config[config_key::cert].toString().toUtf8()),
|
||||||
|
QByteArray::fromBase64(m_ikev2_config[config_key::cert].toString().toUtf8()).size());
|
||||||
|
|
||||||
|
PKCS12 *pkcs12 = d2i_PKCS12_bio(p12, NULL);
|
||||||
|
PKCS12_parse(pkcs12, m_ikev2_config[config_key::password].toString().toStdString().c_str(), &pkey, &cert, &certstack);
|
||||||
|
|
||||||
|
// We output everything in PEM
|
||||||
|
obio = BIO_new(BIO_s_mem());
|
||||||
|
|
||||||
|
// TODO: support protecting the private key with a PEM passphrase
|
||||||
|
if (pkey)
|
||||||
|
{
|
||||||
|
PEM_write_bio_PrivateKey(obio, pkey, NULL, NULL, 0, NULL, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cert)
|
||||||
|
{
|
||||||
|
PEM_write_bio_X509(obio, cert);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (certstack && sk_X509_num(certstack))
|
||||||
|
{
|
||||||
|
for (int i = 0; i < sk_X509_num(certstack); i++)
|
||||||
|
PEM_write_bio_X509_AUX(obio, sk_X509_value(certstack, i));
|
||||||
|
}
|
||||||
|
|
||||||
|
BIO_get_mem_ptr(obio, &bptr);
|
||||||
|
|
||||||
|
output = [NSData dataWithBytes: bptr->data length: bptr->length];
|
||||||
|
|
||||||
|
NSData *PKCS12Data = [[NSData alloc] initWithBase64EncodedString:m_ikev2_config[config_key::cert].toString().toNSString() options:0];
|
||||||
|
|
||||||
|
CFArrayRef items = CFArrayCreate(NULL, 0, 0, NULL);
|
||||||
|
OSStatus ret = SecPKCS12Import(
|
||||||
|
(__bridge CFDataRef)output,
|
||||||
|
(__bridge CFDictionaryRef)@{(id)kSecImportExportPassphrase:@""},
|
||||||
|
&items);
|
||||||
|
|
||||||
|
if (ret != errSecSuccess) {
|
||||||
|
qDebug() << "import err ret " << ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
NSDictionary *firstItem = [(__bridge_transfer NSArray *)items firstObject];
|
||||||
|
SecIdentityRef identity = (__bridge SecIdentityRef)(firstItem[(__bridge id)kSecImportItemIdentity]);
|
||||||
|
|
||||||
|
NEVPNProtocolIKEv2 *protocol = [[NEVPNProtocolIKEv2 alloc] init];
|
||||||
|
protocol.serverAddress = m_ikev2_config.value(amnezia::config_key::hostName).toString().toNSString();
|
||||||
|
protocol.certificateType = NEVPNIKEv2CertificateTypeRSA;
|
||||||
|
|
||||||
|
protocol.remoteIdentifier = m_ikev2_config.value(amnezia::config_key::hostName).toString().toNSString();
|
||||||
|
protocol.authenticationMethod = NEVPNIKEAuthenticationMethodCertificate;
|
||||||
|
protocol.identityReference = searchKeychainCopyMatching(m_ikev2_config.value(amnezia::config_key::userName).toString().toLocal8Bit().data());
|
||||||
|
|
||||||
|
protocol.useExtendedAuthentication = NO;
|
||||||
|
protocol.enablePFS = YES;
|
||||||
|
|
||||||
|
protocol.IKESecurityAssociationParameters.encryptionAlgorithm = NEVPNIKEv2EncryptionAlgorithmAES256;
|
||||||
|
protocol.IKESecurityAssociationParameters.diffieHellmanGroup = NEVPNIKEv2DiffieHellmanGroup19;
|
||||||
|
protocol.IKESecurityAssociationParameters.integrityAlgorithm = NEVPNIKEv2IntegrityAlgorithmSHA256;
|
||||||
|
protocol.IKESecurityAssociationParameters.lifetimeMinutes = 1440;
|
||||||
|
|
||||||
|
protocol.childSecurityAssociationParameters.encryptionAlgorithm = NEVPNIKEv2EncryptionAlgorithmAES256;
|
||||||
|
protocol.childSecurityAssociationParameters.diffieHellmanGroup = NEVPNIKEv2DiffieHellmanGroup19;
|
||||||
|
protocol.childSecurityAssociationParameters.integrityAlgorithm = NEVPNIKEv2IntegrityAlgorithmSHA256;
|
||||||
|
protocol.childSecurityAssociationParameters.lifetimeMinutes = 1440;
|
||||||
|
|
||||||
|
[manager setEnabled:YES];
|
||||||
|
[manager setProtocolConfiguration:(protocol)];
|
||||||
|
[manager setOnDemandEnabled:NO];
|
||||||
|
[manager setLocalizedDescription:@"Amnezia VPN"];
|
||||||
|
|
||||||
|
#ifdef QT_DEBUG
|
||||||
|
NSString *strProtocol = [NSString stringWithFormat:@"{Protocol: %@", protocol];
|
||||||
|
qDebug() << QString::fromNSString(strProtocol);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// do config stuff
|
||||||
|
[manager saveToPreferencesWithCompletionHandler:^(NSError *err)
|
||||||
|
{
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
qDebug() << "First save vpn preferences failed:" << QString::fromNSString(err.localizedDescription);
|
||||||
|
setConnectionState(Vpn::ConnectionState::Disconnected);
|
||||||
|
mutexLocal.unlock();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// load and save preferences again, otherwise Mac bug (https://forums.developer.apple.com/thread/25928)
|
||||||
|
[manager loadFromPreferencesWithCompletionHandler:^(NSError *err)
|
||||||
|
{
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
qDebug() << "Second load vpn preferences failed:" << QString::fromNSString(err.localizedDescription);
|
||||||
|
setConnectionState(Vpn::ConnectionState::Disconnected);
|
||||||
|
mutexLocal.unlock();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
[manager saveToPreferencesWithCompletionHandler:^(NSError *err)
|
||||||
|
{
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
qDebug() << "Second Save vpn preferences failed:" << QString::fromNSString(err.localizedDescription);
|
||||||
|
setConnectionState(Vpn::ConnectionState::Disconnected);
|
||||||
|
mutexLocal.unlock();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
notificationId_ = [[NSNotificationCenter defaultCenter] addObserverForName: (NSString *)NEVPNStatusDidChangeNotification object: manager.connection queue: nil usingBlock: ^ (NSNotification *notification)
|
||||||
|
{
|
||||||
|
this->handleNotification(notification);
|
||||||
|
}];
|
||||||
|
|
||||||
|
qDebug() << "NEVPNConnection current status:" << (int)manager.connection.status;
|
||||||
|
|
||||||
|
NSError *startError;
|
||||||
|
[manager.connection startVPNTunnelAndReturnError:&startError];
|
||||||
|
if (startError)
|
||||||
|
{
|
||||||
|
qDebug() << "Error starting ikev2 connection:" << QString::fromNSString(startError.localizedDescription);
|
||||||
|
[[NSNotificationCenter defaultCenter] removeObserver: (id)notificationId_ name: (NSString *)NEVPNStatusDidChangeNotification object: manager.connection];
|
||||||
|
setConnectionState(Vpn::ConnectionState::Disconnected);
|
||||||
|
}
|
||||||
|
mutexLocal.unlock();
|
||||||
|
}
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
}];
|
||||||
|
|
||||||
|
mutexLocal.unlock();
|
||||||
|
|
||||||
|
setConnectionState(Vpn::ConnectionState::Connected);
|
||||||
|
return ErrorCode::NoError;
|
||||||
|
}
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
bool Ikev2Protocol::create_new_vpn(const QString & vpn_name,
|
||||||
|
const QString & serv_addr) {
|
||||||
|
qDebug() << "Ikev2Protocol::create_new_vpn()";
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
bool Ikev2Protocol::delete_vpn_connection(const QString &vpn_name) {
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
bool Ikev2Protocol::connect_to_vpn(const QString & vpn_name) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
bool Ikev2Protocol::disconnect_vpn() {
|
||||||
|
|
||||||
|
NEVPNManager *manager = [NEVPNManager sharedManager];
|
||||||
|
|
||||||
|
// #713: If user had started connecting to IKev2 on Mac and quickly started after this connecting to Wireguard
|
||||||
|
|
||||||
|
// then manager.connection.status doesn't have time to change to NEVPNStatusConnecting
|
||||||
|
// and remains NEVPNStatusDisconnected as it was before connection tries.
|
||||||
|
// Then we should check below isConnectingStateReachedAfterStartingConnection_ flag to be sure that connecting started.
|
||||||
|
// Without this check we will start connecting to the Wireguard when IKEv2 connecting process hasn't finished yet.
|
||||||
|
if (manager.connection.status == NEVPNStatusDisconnected && isConnectingStateReachedAfterStartingConnection_)
|
||||||
|
{
|
||||||
|
[[NSNotificationCenter defaultCenter] removeObserver: (id)notificationId_ name: (NSString *)NEVPNStatusDidChangeNotification object: manager.connection];
|
||||||
|
setConnectionState(Vpn::ConnectionState::Disconnected);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
[manager.connection stopVPNTunnel];
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Ikev2Protocol::closeWindscribeActiveConnection()
|
||||||
|
{
|
||||||
|
|
||||||
|
NEVPNManager *manager = [NEVPNManager sharedManager];
|
||||||
|
if (manager)
|
||||||
|
{
|
||||||
|
[manager loadFromPreferencesWithCompletionHandler:^(NSError *err)
|
||||||
|
{
|
||||||
|
if (!err)
|
||||||
|
{
|
||||||
|
NEVPNConnection * connection = [manager connection];
|
||||||
|
if (connection.status == NEVPNStatusConnected || connection.status == NEVPNStatusConnecting)
|
||||||
|
{
|
||||||
|
if ([manager.localizedDescription isEqualToString:@"Amnezia VPN"] == YES)
|
||||||
|
{
|
||||||
|
qDebug() << "Previous IKEv2 connection is active. Stop it.";
|
||||||
|
[connection stopVPNTunnel];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void Ikev2Protocol::handleNotificationImpl(int status)
|
||||||
|
{
|
||||||
|
QMutexLocker locker(&mutex_);
|
||||||
|
|
||||||
|
NEVPNManager *manager = [NEVPNManager sharedManager];
|
||||||
|
|
||||||
|
if (status == NEVPNStatusInvalid)
|
||||||
|
{
|
||||||
|
qDebug() << "Connection status changed: NEVPNStatusInvalid";
|
||||||
|
[[NSNotificationCenter defaultCenter] removeObserver: (id)notificationId_ name: (NSString *)NEVPNStatusDidChangeNotification object: manager.connection];
|
||||||
|
setConnectionState(Vpn::ConnectionState::Disconnected);
|
||||||
|
}
|
||||||
|
else if (status == NEVPNStatusDisconnected)
|
||||||
|
{
|
||||||
|
qDebug() << "Connection status changed: NEVPNStatusDisconnected";
|
||||||
|
IpcClient::Interface()->disableKillSwitch();
|
||||||
|
|
||||||
|
setConnectionState(Vpn::ConnectionState::Disconnected);
|
||||||
|
[[NSNotificationCenter defaultCenter] removeObserver: (id)notificationId_ name: (NSString *)NEVPNStatusDidChangeNotification object: manager.connection];
|
||||||
|
|
||||||
|
}
|
||||||
|
else if (status == NEVPNStatusConnecting)
|
||||||
|
{
|
||||||
|
isConnectingStateReachedAfterStartingConnection_ = true;
|
||||||
|
setConnectionState(Vpn::ConnectionState::Connecting);
|
||||||
|
qDebug() << "Connection status changed: NEVPNStatusConnecting";
|
||||||
|
}
|
||||||
|
else if (status == NEVPNStatusConnected)
|
||||||
|
{
|
||||||
|
qDebug() << "Connection status changed: NEVPNStatusConnected";
|
||||||
|
|
||||||
|
QString ipsecAdapterName_ = NetworkUtilities::lastConnectedNetworkInterfaceName();
|
||||||
|
m_vpnLocalAddress = NetworkUtilities::ipAddressByInterfaceName(ipsecAdapterName_);
|
||||||
|
m_vpnGateway = m_vpnLocalAddress;
|
||||||
|
|
||||||
|
QList<QHostAddress> dnsAddr;
|
||||||
|
dnsAddr.push_back(QHostAddress(m_config.value(config_key::dns1).toString()));
|
||||||
|
dnsAddr.push_back(QHostAddress(m_config.value(config_key::dns2).toString()));
|
||||||
|
|
||||||
|
IpcClient::Interface()->updateResolvers(ipsecAdapterName_, dnsAddr);
|
||||||
|
|
||||||
|
if (QVariant(m_config.value(config_key::killSwitchOption).toString()).toBool()) {
|
||||||
|
qDebug() << "enable killswitch";
|
||||||
|
IpcClient::Interface()->enableKillSwitch(m_config, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
setConnectionState(Vpn::ConnectionState::Connected);
|
||||||
|
}
|
||||||
|
else if (status == NEVPNStatusReasserting)
|
||||||
|
{
|
||||||
|
qDebug() << "Connection status changed: NEVPNStatusReasserting";
|
||||||
|
setConnectionState(Vpn::ConnectionState::Connecting);
|
||||||
|
}
|
||||||
|
else if (status == NEVPNStatusDisconnecting)
|
||||||
|
{
|
||||||
|
qDebug() << "Connection status changed: NEVPNStatusDisconnecting";
|
||||||
|
setConnectionState(Vpn::ConnectionState::Disconnecting);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Ikev2Protocol::handleNotification(void *notification)
|
||||||
|
{
|
||||||
|
QMutexLocker locker(&mutex_);
|
||||||
|
NSNotification *nsNotification = (NSNotification *)notification;
|
||||||
|
NEVPNConnection *connection = nsNotification.object;
|
||||||
|
QMetaObject::invokeMethod(this, "handleNotificationImpl", Q_ARG(int, (int)connection.status));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -172,7 +172,8 @@ void Ikev2Protocol::newConnectionStateEventReceived(UINT unMsg, tagRASCONNSTATE
|
||||||
|
|
||||||
void Ikev2Protocol::readIkev2Configuration(const QJsonObject &configuration)
|
void Ikev2Protocol::readIkev2Configuration(const QJsonObject &configuration)
|
||||||
{
|
{
|
||||||
m_config = configuration.value(ProtocolProps::key_proto_config_data(Proto::Ikev2)).toObject();
|
QJsonObject ikev2_data = configuration.value(ProtocolProps::key_proto_config_data(Proto::Ikev2)).toObject();
|
||||||
|
m_config = QJsonDocument::fromJson(ikev2_data.value(config_key::config).toString().toUtf8()).object();
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorCode Ikev2Protocol::start()
|
ErrorCode Ikev2Protocol::start()
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@ namespace amnezia
|
||||||
constexpr char description[] = "description";
|
constexpr char description[] = "description";
|
||||||
constexpr char name[] = "name";
|
constexpr char name[] = "name";
|
||||||
constexpr char cert[] = "cert";
|
constexpr char cert[] = "cert";
|
||||||
|
constexpr char cacert[] = "cacert";
|
||||||
constexpr char config[] = "config";
|
constexpr char config[] = "config";
|
||||||
|
|
||||||
constexpr char containers[] = "containers";
|
constexpr char containers[] = "containers";
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,14 @@
|
||||||
#include "ikev2_vpn_protocol_windows.h"
|
#include "ikev2_vpn_protocol_windows.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef Q_OS_LINUX
|
||||||
|
#include "ikev2_vpn_protocol_linux.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef Q_OS_MACX
|
||||||
|
#include "ikev2_vpn_protocol_mac.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
VpnProtocol::VpnProtocol(const QJsonObject &configuration, QObject *parent)
|
VpnProtocol::VpnProtocol(const QJsonObject &configuration, QObject *parent)
|
||||||
: QObject(parent),
|
: QObject(parent),
|
||||||
m_connectionState(Vpn::ConnectionState::Unknown),
|
m_connectionState(Vpn::ConnectionState::Unknown),
|
||||||
|
|
@ -106,9 +114,6 @@ QString VpnProtocol::vpnGateway() const
|
||||||
VpnProtocol *VpnProtocol::factory(DockerContainer container, const QJsonObject &configuration)
|
VpnProtocol *VpnProtocol::factory(DockerContainer container, const QJsonObject &configuration)
|
||||||
{
|
{
|
||||||
switch (container) {
|
switch (container) {
|
||||||
#if defined(Q_OS_WINDOWS)
|
|
||||||
case DockerContainer::Ipsec: return new Ikev2Protocol(configuration);
|
|
||||||
#endif
|
|
||||||
#if defined(Q_OS_WINDOWS) || defined(Q_OS_MACX) || (defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID))
|
#if defined(Q_OS_WINDOWS) || defined(Q_OS_MACX) || (defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID))
|
||||||
case DockerContainer::OpenVpn: return new OpenVpnProtocol(configuration);
|
case DockerContainer::OpenVpn: return new OpenVpnProtocol(configuration);
|
||||||
case DockerContainer::Cloak: return new OpenVpnOverCloakProtocol(configuration);
|
case DockerContainer::Cloak: return new OpenVpnOverCloakProtocol(configuration);
|
||||||
|
|
@ -117,6 +122,7 @@ VpnProtocol *VpnProtocol::factory(DockerContainer container, const QJsonObject &
|
||||||
case DockerContainer::Awg: return new WireguardProtocol(configuration);
|
case DockerContainer::Awg: return new WireguardProtocol(configuration);
|
||||||
case DockerContainer::Xray: return new XrayProtocol(configuration);
|
case DockerContainer::Xray: return new XrayProtocol(configuration);
|
||||||
case DockerContainer::SSXray: return new XrayProtocol(configuration);
|
case DockerContainer::SSXray: return new XrayProtocol(configuration);
|
||||||
|
case DockerContainer::Ipsec: return new Ikev2Protocol(configuration);
|
||||||
#endif
|
#endif
|
||||||
default: return nullptr;
|
default: return nullptr;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -199,6 +199,7 @@
|
||||||
<file>server_scripts/socks5_proxy/Dockerfile</file>
|
<file>server_scripts/socks5_proxy/Dockerfile</file>
|
||||||
<file>server_scripts/socks5_proxy/configure_container.sh</file>
|
<file>server_scripts/socks5_proxy/configure_container.sh</file>
|
||||||
<file>server_scripts/socks5_proxy/start.sh</file>
|
<file>server_scripts/socks5_proxy/start.sh</file>
|
||||||
|
<file>server_scripts/ipsec/template.conf</file>
|
||||||
<file>ui/qml/Pages2/PageProtocolAwgClientSettings.qml</file>
|
<file>ui/qml/Pages2/PageProtocolAwgClientSettings.qml</file>
|
||||||
<file>ui/qml/Pages2/PageProtocolWireGuardClientSettings.qml</file>
|
<file>ui/qml/Pages2/PageProtocolWireGuardClientSettings.qml</file>
|
||||||
<file>ui/qml/Pages2/PageSetupWizardApiServicesList.qml</file>
|
<file>ui/qml/Pages2/PageSetupWizardApiServicesList.qml</file>
|
||||||
|
|
|
||||||
|
|
@ -242,6 +242,7 @@ conn ikev2-cp
|
||||||
dpdtimeout=120
|
dpdtimeout=120
|
||||||
dpdaction=clear
|
dpdaction=clear
|
||||||
auto=add
|
auto=add
|
||||||
|
authby=rsa-sha1
|
||||||
ikev2=insist
|
ikev2=insist
|
||||||
rekey=no
|
rekey=no
|
||||||
pfs=no
|
pfs=no
|
||||||
|
|
|
||||||
27
client/server_scripts/ipsec/template.conf
Normal file
27
client/server_scripts/ipsec/template.conf
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
config setup
|
||||||
|
charondebug="ike 1, knl 1, cfg 0"
|
||||||
|
uniqueids=no
|
||||||
|
|
||||||
|
conn ikev2-vpn
|
||||||
|
auto=add
|
||||||
|
type=tunnel
|
||||||
|
keyexchange=ikev2
|
||||||
|
fragmentation=yes
|
||||||
|
forceencaps=yes
|
||||||
|
dpdaction=clear
|
||||||
|
dpddelay=300s
|
||||||
|
rekey=no
|
||||||
|
leftid=$CLIENT_NAME
|
||||||
|
leftcert=$CLIENT_NAME.crt
|
||||||
|
leftdns=$PRIMARY_DNS,$SECONDARY_DNS
|
||||||
|
leftsendcert=always
|
||||||
|
leftsourceip=%config
|
||||||
|
right=$SERVER_IP_ADDRESS
|
||||||
|
rightsubnet=0.0.0.0/0
|
||||||
|
rightsendcert=never
|
||||||
|
eap_identity=%identity
|
||||||
|
encapsulation=yes
|
||||||
|
ike=aes256-sha256-modp2048,aes256-sha1-modp1024,3des-sha1-modp1024
|
||||||
|
esp=aes256-sha256,aes256-sha1,3des-sha1
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,9 +1,11 @@
|
||||||
# Exempt the tunnel interface(s) used by the VPN connection
|
# Exempt the tunnel interface(s) used by the VPN connection
|
||||||
|
|
||||||
utunInterfaces = "{ \
|
utunInterfaces = "{ \
|
||||||
utun0, utun1, utun2, utun3, utun4, utun5, utun6, utun7, utun8, utun9, utun10, \
|
utun0, utun1, utun2, utun3, utun4, utun5, utun6, utun7, utun8, utun9, utun10, \
|
||||||
utun11, utun12, utun13, utun14, utun15, utun16, utun17, utun18, utun19, utun20, \
|
utun11, utun12, utun13, utun14, utun15, utun16, utun17, utun18, utun19, utun20, \
|
||||||
utun21, utun22, utun23, utun24, utun25, utun26, utun27, utun28, utun29, utun30 \
|
utun21, utun22, utun23, utun24, utun25, utun26, utun27, utun28, utun29, utun30, \
|
||||||
|
ipsec0, ipsec1, ipsec2, ipsec3, ipsec4, ipsec5, ipsec6, ipsec7, ipsec8, ipsec9, \
|
||||||
|
ipsec10, ipsec11, ipsec12, ipsec13, ipsec14, ipsec15, ipsec16, ipsec17, ipsec18, ipsec19 \
|
||||||
}"
|
}"
|
||||||
|
|
||||||
pass out on $utunInterfaces flags any no state
|
pass out on $utunInterfaces flags any no state
|
||||||
|
|
|
||||||
|
|
@ -32,5 +32,17 @@ class IpcInterface
|
||||||
SLOT( bool enablePeerTraffic( const QJsonObject &configStr) );
|
SLOT( bool enablePeerTraffic( const QJsonObject &configStr) );
|
||||||
SLOT( bool enableKillSwitch( const QJsonObject &excludeAddr, int vpnAdapterIndex) );
|
SLOT( bool enableKillSwitch( const QJsonObject &excludeAddr, int vpnAdapterIndex) );
|
||||||
SLOT( bool updateResolvers(const QString& ifname, const QList<QHostAddress>& resolvers) );
|
SLOT( bool updateResolvers(const QString& ifname, const QList<QHostAddress>& resolvers) );
|
||||||
|
|
||||||
|
SLOT( bool writeIPsecCaCert(QString cacert, QString uuid) );
|
||||||
|
SLOT( bool writeIPsecPrivate(QString privKey, QString uuid) );
|
||||||
|
SLOT( bool writeIPsecConfig(QString config) );
|
||||||
|
SLOT( bool writeIPsecUserCert(QString usercert, QString uuid) );
|
||||||
|
SLOT( bool writeIPsecPrivatePass(QString pass, QString host, QString uuid) );
|
||||||
|
|
||||||
|
SLOT( bool stopIPsec(QString tunnelName) );
|
||||||
|
SLOT( bool startIPsec(QString tunnelName) );
|
||||||
|
|
||||||
|
SLOT( QString getTunnelStatus(QString tunnelName) );
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,9 +4,11 @@
|
||||||
#include <QFileInfo>
|
#include <QFileInfo>
|
||||||
#include <QLocalSocket>
|
#include <QLocalSocket>
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
|
#include <QJsonArray>
|
||||||
|
|
||||||
#include "logger.h"
|
#include "qjsonarray.h"
|
||||||
#include "router.h"
|
#include "router.h"
|
||||||
|
#include "logger.h"
|
||||||
|
|
||||||
#include "../core/networkUtilities.h"
|
#include "../core/networkUtilities.h"
|
||||||
#include "../client/protocols/protocols_defs.h"
|
#include "../client/protocols/protocols_defs.h"
|
||||||
|
|
@ -174,6 +176,7 @@ void IpcServer::StartRoutingIpv6()
|
||||||
{
|
{
|
||||||
Router::StartRoutingIpv6();
|
Router::StartRoutingIpv6();
|
||||||
}
|
}
|
||||||
|
|
||||||
void IpcServer::StopRoutingIpv6()
|
void IpcServer::StopRoutingIpv6()
|
||||||
{
|
{
|
||||||
Router::StopRoutingIpv6();
|
Router::StopRoutingIpv6();
|
||||||
|
|
@ -275,7 +278,6 @@ bool IpcServer::enableKillSwitch(const QJsonObject &configStr, int vpnAdapterInd
|
||||||
MacOSFirewall::setAnchorEnabled(QStringLiteral("310.blockDNS"), true);
|
MacOSFirewall::setAnchorEnabled(QStringLiteral("310.blockDNS"), true);
|
||||||
MacOSFirewall::setAnchorTable(QStringLiteral("310.blockDNS"), true, QStringLiteral("dnsaddr"), dnsServers);
|
MacOSFirewall::setAnchorTable(QStringLiteral("310.blockDNS"), true, QStringLiteral("dnsaddr"), dnsServers);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -296,6 +298,196 @@ bool IpcServer::disableKillSwitch()
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool IpcServer::startIPsec(QString tunnelName)
|
||||||
|
{
|
||||||
|
#ifdef Q_OS_LINUX
|
||||||
|
QProcess processSystemd;
|
||||||
|
QStringList commandsSystemd;
|
||||||
|
commandsSystemd << "systemctl" << "restart" << "ipsec";
|
||||||
|
processSystemd.start("sudo", commandsSystemd);
|
||||||
|
if (!processSystemd.waitForStarted(1000))
|
||||||
|
{
|
||||||
|
qDebug().noquote() << "Could not start ipsec tunnel!\n";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else if (!processSystemd.waitForFinished(2000))
|
||||||
|
{
|
||||||
|
qDebug().noquote() << "Could not start ipsec tunnel\n";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
commandsSystemd.clear();
|
||||||
|
|
||||||
|
QThread::msleep(5000);
|
||||||
|
|
||||||
|
QProcess process;
|
||||||
|
QStringList commands;
|
||||||
|
commands << "ipsec" << "up" << QString("%1").arg(tunnelName);
|
||||||
|
process.start("sudo", commands);
|
||||||
|
if (!process.waitForStarted(1000))
|
||||||
|
{
|
||||||
|
qDebug().noquote() << "Could not start ipsec tunnel!\n";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else if (!process.waitForFinished(2000))
|
||||||
|
{
|
||||||
|
qDebug().noquote() << "Could not start ipsec tunnel\n";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
commands.clear();
|
||||||
|
#endif
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IpcServer::stopIPsec(QString tunnelName)
|
||||||
|
{
|
||||||
|
#ifdef Q_OS_LINUX
|
||||||
|
QProcess process;
|
||||||
|
QStringList commands;
|
||||||
|
commands << "ipsec" << "down" << QString("%1").arg(tunnelName);
|
||||||
|
process.start("sudo", commands);
|
||||||
|
if (!process.waitForStarted(1000))
|
||||||
|
{
|
||||||
|
qDebug().noquote() << "Could not stop ipsec tunnel\n";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else if (!process.waitForFinished(2000))
|
||||||
|
{
|
||||||
|
qDebug().noquote() << "Could not stop ipsec tunnel\n";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
commands.clear();
|
||||||
|
#endif
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IpcServer::writeIPsecConfig(QString config)
|
||||||
|
{
|
||||||
|
#ifdef Q_OS_LINUX
|
||||||
|
qDebug() << "IPSEC: IPSec config file";
|
||||||
|
QString configFile = QString("/etc/ipsec.conf");
|
||||||
|
QFile ipSecConfFile(configFile);
|
||||||
|
if (ipSecConfFile.open(QIODevice::WriteOnly)) {
|
||||||
|
ipSecConfFile.write(config.toUtf8());
|
||||||
|
ipSecConfFile.close();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IpcServer::writeIPsecUserCert(QString usercert, QString uuid)
|
||||||
|
{
|
||||||
|
#ifdef Q_OS_LINUX
|
||||||
|
qDebug() << "IPSEC: Write user cert " << uuid;
|
||||||
|
QString certName = QString("/etc/ipsec.d/certs/%1.crt").arg(uuid);
|
||||||
|
QFile userCertFile(certName);
|
||||||
|
if (userCertFile.open(QIODevice::WriteOnly)) {
|
||||||
|
userCertFile.write(usercert.toUtf8());
|
||||||
|
userCertFile.close();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IpcServer::writeIPsecCaCert(QString cacert, QString uuid)
|
||||||
|
{
|
||||||
|
#ifdef Q_OS_LINUX
|
||||||
|
qDebug() << "IPSEC: Write CA cert user " << uuid;
|
||||||
|
QString certName = QString("/etc/ipsec.d/cacerts/%1.crt").arg(uuid);
|
||||||
|
QFile caCertFile(certName);
|
||||||
|
if (caCertFile.open(QIODevice::WriteOnly)) {
|
||||||
|
caCertFile.write(cacert.toUtf8());
|
||||||
|
caCertFile.close();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IpcServer::writeIPsecPrivate(QString privKey, QString uuid)
|
||||||
|
{
|
||||||
|
#ifdef Q_OS_LINUX
|
||||||
|
qDebug() << "IPSEC: User private key " << uuid;
|
||||||
|
QString privateKey = QString("/etc/ipsec.d/private/%1.p12").arg(uuid);
|
||||||
|
QFile pKeyFile(privateKey);
|
||||||
|
if (pKeyFile.open(QIODevice::WriteOnly)) {
|
||||||
|
pKeyFile.write(QByteArray::fromBase64(privKey.toUtf8()));
|
||||||
|
pKeyFile.close();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool IpcServer::writeIPsecPrivatePass(QString pass, QString host, QString uuid)
|
||||||
|
{
|
||||||
|
#ifdef Q_OS_LINUX
|
||||||
|
qDebug() << "IPSEC: User private key " << uuid;
|
||||||
|
const QString secretsFilename = "/etc/ipsec.secrets";
|
||||||
|
QStringList lines;
|
||||||
|
|
||||||
|
{
|
||||||
|
QFile secretsFile(secretsFilename);
|
||||||
|
if (secretsFile.open(QIODevice::ReadOnly | QIODevice::Text))
|
||||||
|
{
|
||||||
|
QTextStream edit(&secretsFile);
|
||||||
|
while (!edit.atEnd()) lines.push_back(edit.readLine());
|
||||||
|
}
|
||||||
|
secretsFile.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto iter = lines.begin(); iter!=lines.end();)
|
||||||
|
{
|
||||||
|
if (iter->contains(host))
|
||||||
|
{
|
||||||
|
iter = lines.erase(iter);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
++iter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
QFile secretsFile(secretsFilename);
|
||||||
|
if (secretsFile.open(QIODevice::WriteOnly | QIODevice::Text))
|
||||||
|
{
|
||||||
|
QTextStream edit(&secretsFile);
|
||||||
|
for (int i=0; i<lines.size(); i++) edit << lines[i] << Qt::endl;
|
||||||
|
}
|
||||||
|
QString P12 = QString("%any %1 : P12 %2.p12 \"%3\" \n").arg(host, uuid, pass);
|
||||||
|
secretsFile.write(P12.toUtf8());
|
||||||
|
secretsFile.close();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString IpcServer::getTunnelStatus(QString tunnelName)
|
||||||
|
{
|
||||||
|
#ifdef Q_OS_LINUX
|
||||||
|
QProcess process;
|
||||||
|
QStringList commands;
|
||||||
|
commands << "ipsec" << "status" << QString("%1").arg(tunnelName);
|
||||||
|
process.start("sudo", commands);
|
||||||
|
if (!process.waitForStarted(1000))
|
||||||
|
{
|
||||||
|
qDebug().noquote() << "Could not stop ipsec tunnel\n";
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
else if (!process.waitForFinished(2000))
|
||||||
|
{
|
||||||
|
qDebug().noquote() << "Could not stop ipsec tunnel\n";
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
commands.clear();
|
||||||
|
|
||||||
|
|
||||||
|
QString status = process.readAll();
|
||||||
|
return status;
|
||||||
|
#endif
|
||||||
|
return QString();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
bool IpcServer::enablePeerTraffic(const QJsonObject &configStr)
|
bool IpcServer::enablePeerTraffic(const QJsonObject &configStr)
|
||||||
{
|
{
|
||||||
#ifdef Q_OS_WIN
|
#ifdef Q_OS_WIN
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,14 @@ public:
|
||||||
virtual bool enableKillSwitch(const QJsonObject &excludeAddr, int vpnAdapterIndex) override;
|
virtual bool enableKillSwitch(const QJsonObject &excludeAddr, int vpnAdapterIndex) override;
|
||||||
virtual bool disableKillSwitch() override;
|
virtual bool disableKillSwitch() override;
|
||||||
virtual bool updateResolvers(const QString& ifname, const QList<QHostAddress>& resolvers) override;
|
virtual bool updateResolvers(const QString& ifname, const QList<QHostAddress>& resolvers) override;
|
||||||
|
virtual bool writeIPsecCaCert(QString cacert, QString uuid) override;
|
||||||
|
virtual bool writeIPsecPrivate(QString privKey, QString uuid) override;
|
||||||
|
virtual bool writeIPsecConfig(QString config) override;
|
||||||
|
virtual bool writeIPsecUserCert(QString usercert, QString uuid) override;
|
||||||
|
virtual bool writeIPsecPrivatePass(QString pass, QString host, QString uuid) override;
|
||||||
|
virtual bool stopIPsec(QString tunnelName) override;
|
||||||
|
virtual bool startIPsec(QString tunnelName) override;
|
||||||
|
virtual QString getTunnelStatus(QString tunnelName) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int m_localpid = 0;
|
int m_localpid = 0;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue