Killswitch and Splittunnel for MacOS IPSec
This commit is contained in:
parent
f0e66e4ecf
commit
a144d495ee
4 changed files with 184 additions and 173 deletions
|
|
@ -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>
|
||||||
|
|
@ -460,3 +467,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
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,6 @@ public:
|
||||||
bool connect_to_vpn(const QString & vpn_name);
|
bool connect_to_vpn(const QString & vpn_name);
|
||||||
bool disconnect_vpn();
|
bool disconnect_vpn();
|
||||||
void closeWindscribeActiveConnection();
|
void closeWindscribeActiveConnection();
|
||||||
|
|
||||||
ErrorCode start() override;
|
ErrorCode start() override;
|
||||||
void stop() override;
|
void stop() override;
|
||||||
|
|
||||||
|
|
@ -30,29 +29,13 @@ private slots:
|
||||||
void handleNotificationImpl(int status);
|
void handleNotificationImpl(int status);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
enum {STATE_DISCONNECTED, STATE_START_CONNECT, STATE_START_DISCONNECTING, STATE_CONNECTED, STATE_DISCONNECTING_AUTH_ERROR, STATE_DISCONNECTING_ANY_ERROR};
|
|
||||||
|
|
||||||
int state_;
|
|
||||||
|
|
||||||
bool bConnected_;
|
|
||||||
mutable QRecursiveMutex mutex_;
|
mutable QRecursiveMutex mutex_;
|
||||||
void *notificationId_;
|
void *notificationId_;
|
||||||
bool isStateConnectingAfterClick_;
|
|
||||||
bool isDisconnectClicked_;
|
|
||||||
|
|
||||||
QString overrideDnsIp_;
|
|
||||||
|
|
||||||
QJsonObject m_config;
|
QJsonObject m_config;
|
||||||
|
QJsonObject m_ikev2_config;
|
||||||
|
|
||||||
static constexpr int STATISTICS_UPDATE_PERIOD = 1000;
|
|
||||||
QTimer statisticsTimer_;
|
|
||||||
QString ipsecAdapterName_;
|
QString ipsecAdapterName_;
|
||||||
|
|
||||||
int prevConnectionStatus_;
|
|
||||||
bool isPrevConnectionStatusInitialized_;
|
|
||||||
|
|
||||||
// True if startConnect() method was called and NEVPNManager emitted notification NEVPNStatusConnecting.
|
|
||||||
// False otherwise.
|
|
||||||
bool isConnectingStateReachedAfterStartingConnection_;
|
bool isConnectingStateReachedAfterStartingConnection_;
|
||||||
|
|
||||||
void handleNotification(void *notification);
|
void handleNotification(void *notification);
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
#include "ikev2_vpn_protocol_mac.h"
|
#include "ikev2_vpn_protocol_mac.h"
|
||||||
|
|
||||||
|
#include <core/networkUtilities.h>
|
||||||
|
|
||||||
#include <SystemConfiguration/SCSchemaDefinitions.h>
|
#include <SystemConfiguration/SCSchemaDefinitions.h>
|
||||||
#include <SystemConfiguration/SCNetwork.h>
|
#include <SystemConfiguration/SCNetwork.h>
|
||||||
#include <SystemConfiguration/SCNetworkConnection.h>
|
#include <SystemConfiguration/SCNetworkConnection.h>
|
||||||
|
|
@ -20,16 +19,15 @@
|
||||||
#include <net/if.h>
|
#include <net/if.h>
|
||||||
#include <net/route.h>
|
#include <net/route.h>
|
||||||
|
|
||||||
static NSString * const IKEv1ServiceName = @"AmneziaVPN";
|
|
||||||
static NSString * const IKEv2ServiceName = @"AmneziaVPN IKEv2";
|
static NSString * const IKEv2ServiceName = @"AmneziaVPN IKEv2";
|
||||||
|
|
||||||
static Ikev2Protocol* self = nullptr;
|
static Ikev2Protocol* self = nullptr;
|
||||||
|
|
||||||
|
|
||||||
Ikev2Protocol::Ikev2Protocol(const QJsonObject &configuration, QObject* parent) :
|
Ikev2Protocol::Ikev2Protocol(const QJsonObject &configuration, QObject* parent) :
|
||||||
VpnProtocol(configuration, parent)
|
VpnProtocol(configuration, parent)
|
||||||
{
|
{
|
||||||
qDebug() << "IpsecProtocol::IpsecProtocol()";
|
qDebug() << "IpsecProtocol::IpsecProtocol()";
|
||||||
|
m_routeGateway = NetworkUtilities::getGatewayAndIface();
|
||||||
self = this;
|
self = this;
|
||||||
readIkev2Configuration(configuration);
|
readIkev2Configuration(configuration);
|
||||||
}
|
}
|
||||||
|
|
@ -38,6 +36,7 @@ Ikev2Protocol::~Ikev2Protocol()
|
||||||
{
|
{
|
||||||
qDebug() << "IpsecProtocol::~IpsecProtocol()";
|
qDebug() << "IpsecProtocol::~IpsecProtocol()";
|
||||||
disconnect_vpn();
|
disconnect_vpn();
|
||||||
|
QThread::msleep(1000);
|
||||||
Ikev2Protocol::stop();
|
Ikev2Protocol::stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -47,12 +46,13 @@ void Ikev2Protocol::stop()
|
||||||
qDebug() << "IpsecProtocol::stop()";
|
qDebug() << "IpsecProtocol::stop()";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Ikev2Protocol::readIkev2Configuration(const QJsonObject &configuration)
|
void Ikev2Protocol::readIkev2Configuration(const QJsonObject &configuration)
|
||||||
{
|
{
|
||||||
qDebug() << "IpsecProtocol::readIkev2Configuration";
|
qDebug() << "IpsecProtocol::readIkev2Configuration";
|
||||||
QJsonObject ikev2_data = configuration.value(ProtocolProps::key_proto_config_data(Proto::Ikev2)).toObject();
|
m_config = configuration;
|
||||||
m_config = QJsonDocument::fromJson(ikev2_data.value(config_key::config).toString().toUtf8()).object();
|
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)
|
CFDataRef CreatePersistentRefForIdentity(SecIdentityRef identity)
|
||||||
|
|
@ -75,16 +75,16 @@ CFDataRef CreatePersistentRefForIdentity(SecIdentityRef identity)
|
||||||
|
|
||||||
NSData *searchKeychainCopyMatching(const char *certName)
|
NSData *searchKeychainCopyMatching(const char *certName)
|
||||||
{
|
{
|
||||||
NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
|
NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
|
||||||
[dict setObject:(__bridge id)kSecClassCertificate forKey:(__bridge id)kSecClass];
|
[dict setObject:(__bridge id)kSecClassCertificate forKey:(__bridge id)kSecClass];
|
||||||
[dict setObject:[NSString stringWithUTF8String:certName] forKey:(__bridge id)kSecAttrLabel];
|
[dict setObject:[NSString stringWithUTF8String:certName] forKey:(__bridge id)kSecAttrLabel];
|
||||||
[dict setObject:(__bridge id)kSecMatchLimitOne forKey:(__bridge id)kSecMatchLimit];
|
[dict setObject:(__bridge id)kSecMatchLimitOne forKey:(__bridge id)kSecMatchLimit];
|
||||||
[dict setObject:@YES forKey:(__bridge id)kSecReturnPersistentRef];
|
[dict setObject:@YES forKey:(__bridge id)kSecReturnPersistentRef];
|
||||||
|
|
||||||
CFTypeRef result = NULL;
|
CFTypeRef result = NULL;
|
||||||
SecItemCopyMatching((__bridge CFDictionaryRef)dict, &result);
|
SecItemCopyMatching((__bridge CFDictionaryRef)dict, &result);
|
||||||
|
|
||||||
return (NSData *)result;
|
return (NSData *)result;
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorCode Ikev2Protocol::start()
|
ErrorCode Ikev2Protocol::start()
|
||||||
|
|
@ -122,11 +122,11 @@ ErrorCode Ikev2Protocol::start()
|
||||||
EVP_PKEY *pkey;
|
EVP_PKEY *pkey;
|
||||||
X509 *cert;
|
X509 *cert;
|
||||||
|
|
||||||
BIO_write(p12, QByteArray::fromBase64(m_config[config_key::cert].toString().toUtf8()),
|
BIO_write(p12, QByteArray::fromBase64(m_ikev2_config[config_key::cert].toString().toUtf8()),
|
||||||
QByteArray::fromBase64(m_config[config_key::cert].toString().toUtf8()).size());
|
QByteArray::fromBase64(m_ikev2_config[config_key::cert].toString().toUtf8()).size());
|
||||||
|
|
||||||
PKCS12 *pkcs12 = d2i_PKCS12_bio(p12, NULL);
|
PKCS12 *pkcs12 = d2i_PKCS12_bio(p12, NULL);
|
||||||
PKCS12_parse(pkcs12, m_config[config_key::password].toString().toStdString().c_str(), &pkey, &cert, &certstack);
|
PKCS12_parse(pkcs12, m_ikev2_config[config_key::password].toString().toStdString().c_str(), &pkey, &cert, &certstack);
|
||||||
|
|
||||||
// We output everything in PEM
|
// We output everything in PEM
|
||||||
obio = BIO_new(BIO_s_mem());
|
obio = BIO_new(BIO_s_mem());
|
||||||
|
|
@ -152,7 +152,7 @@ ErrorCode Ikev2Protocol::start()
|
||||||
|
|
||||||
output = [NSData dataWithBytes: bptr->data length: bptr->length];
|
output = [NSData dataWithBytes: bptr->data length: bptr->length];
|
||||||
|
|
||||||
NSData *PKCS12Data = [[NSData alloc] initWithBase64EncodedString:m_config[config_key::cert].toString().toNSString() options:0] ;
|
NSData *PKCS12Data = [[NSData alloc] initWithBase64EncodedString:m_ikev2_config[config_key::cert].toString().toNSString() options:0];
|
||||||
|
|
||||||
CFArrayRef items = CFArrayCreate(NULL, 0, 0, NULL);
|
CFArrayRef items = CFArrayCreate(NULL, 0, 0, NULL);
|
||||||
OSStatus ret = SecPKCS12Import(
|
OSStatus ret = SecPKCS12Import(
|
||||||
|
|
@ -168,12 +168,12 @@ ErrorCode Ikev2Protocol::start()
|
||||||
SecIdentityRef identity = (__bridge SecIdentityRef)(firstItem[(__bridge id)kSecImportItemIdentity]);
|
SecIdentityRef identity = (__bridge SecIdentityRef)(firstItem[(__bridge id)kSecImportItemIdentity]);
|
||||||
|
|
||||||
NEVPNProtocolIKEv2 *protocol = [[NEVPNProtocolIKEv2 alloc] init];
|
NEVPNProtocolIKEv2 *protocol = [[NEVPNProtocolIKEv2 alloc] init];
|
||||||
protocol.serverAddress = m_config.value(amnezia::config_key::hostName).toString().toNSString();
|
protocol.serverAddress = m_ikev2_config.value(amnezia::config_key::hostName).toString().toNSString();
|
||||||
protocol.certificateType = NEVPNIKEv2CertificateTypeRSA;
|
protocol.certificateType = NEVPNIKEv2CertificateTypeRSA;
|
||||||
|
|
||||||
protocol.remoteIdentifier = m_config.value(amnezia::config_key::hostName).toString().toNSString();
|
protocol.remoteIdentifier = m_ikev2_config.value(amnezia::config_key::hostName).toString().toNSString();
|
||||||
protocol.authenticationMethod = NEVPNIKEAuthenticationMethodCertificate;
|
protocol.authenticationMethod = NEVPNIKEAuthenticationMethodCertificate;
|
||||||
protocol.identityReference = searchKeychainCopyMatching(m_config.value(amnezia::config_key::userName).toString().toLocal8Bit().data());
|
protocol.identityReference = searchKeychainCopyMatching(m_ikev2_config.value(amnezia::config_key::userName).toString().toLocal8Bit().data());
|
||||||
|
|
||||||
protocol.useExtendedAuthentication = NO;
|
protocol.useExtendedAuthentication = NO;
|
||||||
protocol.enablePFS = YES;
|
protocol.enablePFS = YES;
|
||||||
|
|
@ -193,8 +193,10 @@ ErrorCode Ikev2Protocol::start()
|
||||||
[manager setOnDemandEnabled:NO];
|
[manager setOnDemandEnabled:NO];
|
||||||
[manager setLocalizedDescription:@"Amnezia VPN"];
|
[manager setLocalizedDescription:@"Amnezia VPN"];
|
||||||
|
|
||||||
|
#ifdef QT_DEBUG
|
||||||
NSString *strProtocol = [NSString stringWithFormat:@"{Protocol: %@", protocol];
|
NSString *strProtocol = [NSString stringWithFormat:@"{Protocol: %@", protocol];
|
||||||
qDebug() << QString::fromNSString(strProtocol);
|
qDebug() << QString::fromNSString(strProtocol);
|
||||||
|
#endif
|
||||||
|
|
||||||
// do config stuff
|
// do config stuff
|
||||||
[manager saveToPreferencesWithCompletionHandler:^(NSError *err)
|
[manager saveToPreferencesWithCompletionHandler:^(NSError *err)
|
||||||
|
|
@ -253,7 +255,6 @@ ErrorCode Ikev2Protocol::start()
|
||||||
}
|
}
|
||||||
}];
|
}];
|
||||||
|
|
||||||
// waitConditionLocal.wait(&mutexLocal);
|
|
||||||
mutexLocal.unlock();
|
mutexLocal.unlock();
|
||||||
|
|
||||||
setConnectionState(Vpn::ConnectionState::Connected);
|
setConnectionState(Vpn::ConnectionState::Connected);
|
||||||
|
|
@ -261,24 +262,22 @@ ErrorCode Ikev2Protocol::start()
|
||||||
}
|
}
|
||||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
bool Ikev2Protocol::create_new_vpn(const QString & vpn_name,
|
bool Ikev2Protocol::create_new_vpn(const QString & vpn_name,
|
||||||
const QString & serv_addr){
|
const QString & serv_addr) {
|
||||||
qDebug() << "Ikev2Protocol::create_new_vpn()";
|
qDebug() << "Ikev2Protocol::create_new_vpn()";
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
bool Ikev2Protocol::delete_vpn_connection(const QString &vpn_name){
|
bool Ikev2Protocol::delete_vpn_connection(const QString &vpn_name) {
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
bool Ikev2Protocol::connect_to_vpn(const QString & vpn_name){
|
bool Ikev2Protocol::connect_to_vpn(const QString & vpn_name) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
bool Ikev2Protocol::disconnect_vpn() {
|
bool Ikev2Protocol::disconnect_vpn() {
|
||||||
|
|
||||||
QMutexLocker locker(&mutex_);
|
|
||||||
|
|
||||||
NEVPNManager *manager = [NEVPNManager sharedManager];
|
NEVPNManager *manager = [NEVPNManager sharedManager];
|
||||||
|
|
||||||
// #713: If user had started connecting to IKev2 on Mac and quickly started after this connecting to Wireguard
|
// #713: If user had started connecting to IKev2 on Mac and quickly started after this connecting to Wireguard
|
||||||
|
|
@ -303,17 +302,12 @@ bool Ikev2Protocol::disconnect_vpn() {
|
||||||
|
|
||||||
void Ikev2Protocol::closeWindscribeActiveConnection()
|
void Ikev2Protocol::closeWindscribeActiveConnection()
|
||||||
{
|
{
|
||||||
static QWaitCondition waitCondition;
|
|
||||||
static QMutex mutex;
|
|
||||||
|
|
||||||
mutex.lock();
|
|
||||||
|
|
||||||
NEVPNManager *manager = [NEVPNManager sharedManager];
|
NEVPNManager *manager = [NEVPNManager sharedManager];
|
||||||
if (manager)
|
if (manager)
|
||||||
{
|
{
|
||||||
[manager loadFromPreferencesWithCompletionHandler:^(NSError *err)
|
[manager loadFromPreferencesWithCompletionHandler:^(NSError *err)
|
||||||
{
|
{
|
||||||
mutex.lock();
|
|
||||||
if (!err)
|
if (!err)
|
||||||
{
|
{
|
||||||
NEVPNConnection * connection = [manager connection];
|
NEVPNConnection * connection = [manager connection];
|
||||||
|
|
@ -326,12 +320,9 @@ void Ikev2Protocol::closeWindscribeActiveConnection()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
waitCondition.wakeAll();
|
|
||||||
mutex.unlock();
|
|
||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
waitCondition.wait(&mutex);
|
|
||||||
mutex.unlock();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Ikev2Protocol::handleNotificationImpl(int status)
|
void Ikev2Protocol::handleNotificationImpl(int status)
|
||||||
|
|
@ -349,44 +340,44 @@ void Ikev2Protocol::handleNotificationImpl(int status)
|
||||||
else if (status == NEVPNStatusDisconnected)
|
else if (status == NEVPNStatusDisconnected)
|
||||||
{
|
{
|
||||||
qDebug() << "Connection status changed: NEVPNStatusDisconnected";
|
qDebug() << "Connection status changed: NEVPNStatusDisconnected";
|
||||||
setConnectionState(Vpn::ConnectionState::Disconnected);
|
IpcClient::Interface()->disableKillSwitch();
|
||||||
if (state_ == STATE_DISCONNECTING_ANY_ERROR)
|
|
||||||
{
|
setConnectionState(Vpn::ConnectionState::Disconnected);
|
||||||
[[NSNotificationCenter defaultCenter] removeObserver: (id)notificationId_ name: (NSString *)NEVPNStatusDidChangeNotification object: manager.connection];
|
[[NSNotificationCenter defaultCenter] removeObserver: (id)notificationId_ name: (NSString *)NEVPNStatusDidChangeNotification object: manager.connection];
|
||||||
// state_ = STATE_DISCONNECTED;
|
|
||||||
// emit error(IKEV_FAILED_TO_CONNECT);
|
|
||||||
setConnectionState(Vpn::ConnectionState::Disconnected);
|
|
||||||
}
|
|
||||||
else if (state_ != STATE_DISCONNECTED)
|
|
||||||
{
|
|
||||||
|
|
||||||
[[NSNotificationCenter defaultCenter] removeObserver: (id)notificationId_ name: (NSString *)NEVPNStatusDidChangeNotification object: manager.connection];
|
|
||||||
// state_ = STATE_DISCONNECTED;
|
|
||||||
setConnectionState(Vpn::ConnectionState::Disconnected);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if (status == NEVPNStatusConnecting)
|
else if (status == NEVPNStatusConnecting)
|
||||||
{
|
{
|
||||||
isConnectingStateReachedAfterStartingConnection_ = true;
|
isConnectingStateReachedAfterStartingConnection_ = true;
|
||||||
|
setConnectionState(Vpn::ConnectionState::Connecting);
|
||||||
qDebug() << "Connection status changed: NEVPNStatusConnecting";
|
qDebug() << "Connection status changed: NEVPNStatusConnecting";
|
||||||
}
|
}
|
||||||
else if (status == NEVPNStatusConnected)
|
else if (status == NEVPNStatusConnected)
|
||||||
{
|
{
|
||||||
if (!overrideDnsIp_.isEmpty()) {
|
|
||||||
if (!setCustomDns(overrideDnsIp_)) {
|
|
||||||
qDebug() << "Failed to set custom DNS ip for ikev2";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
qDebug() << "Connection status changed: 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_config.value(amnezia::config_key::splitTunnelType).toInt() == 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_config.value(amnezia::config_key::hostName).toString());
|
||||||
|
}
|
||||||
|
|
||||||
setConnectionState(Vpn::ConnectionState::Connected);
|
setConnectionState(Vpn::ConnectionState::Connected);
|
||||||
// note: route gateway not used for ikev2 in AdapterGatewayInfo
|
|
||||||
// AdapterGatewayInfo cai;
|
|
||||||
// ipsecAdapterName_ = NetworkUtils_mac::lastConnectedNetworkInterfaceName();
|
|
||||||
// cai.setAdapterName(ipsecAdapterName_);
|
|
||||||
// cai.setAdapterIp(NetworkUtils_mac::ipAddressByInterfaceName(ipsecAdapterName_));
|
|
||||||
//cai.setDnsServers(NetworkUtils_mac::getDnsServersForInterface(ipsecAdapterName_));
|
|
||||||
}
|
}
|
||||||
else if (status == NEVPNStatusReasserting)
|
else if (status == NEVPNStatusReasserting)
|
||||||
{
|
{
|
||||||
|
|
@ -397,33 +388,8 @@ void Ikev2Protocol::handleNotificationImpl(int status)
|
||||||
{
|
{
|
||||||
qDebug() << "Connection status changed: NEVPNStatusDisconnecting";
|
qDebug() << "Connection status changed: NEVPNStatusDisconnecting";
|
||||||
setConnectionState(Vpn::ConnectionState::Disconnecting);
|
setConnectionState(Vpn::ConnectionState::Disconnecting);
|
||||||
/* if (state_ == STATE_START_CONNECT)
|
|
||||||
{
|
|
||||||
QMap<time_t, QString> logs = networkExtensionLog_.collectNext();
|
|
||||||
for (QMap<time_t, QString>::iterator it = logs.begin(); it != logs.end(); ++it)
|
|
||||||
{
|
|
||||||
qDebug() << it.value();
|
|
||||||
}
|
|
||||||
if (isSocketError(logs))
|
|
||||||
{
|
|
||||||
state_ = STATE_DISCONNECTING_ANY_ERROR;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (isFailedAuthError(logs))
|
|
||||||
{
|
|
||||||
state_ = STATE_DISCONNECTING_AUTH_ERROR;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
state_ = STATE_DISCONNECTING_ANY_ERROR;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
prevConnectionStatus_ = status;
|
|
||||||
isPrevConnectionStatusInitialized_ = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -435,62 +401,3 @@ void Ikev2Protocol::handleNotification(void *notification)
|
||||||
QMetaObject::invokeMethod(this, "handleNotificationImpl", Q_ARG(int, (int)connection.status));
|
QMetaObject::invokeMethod(this, "handleNotificationImpl", Q_ARG(int, (int)connection.status));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Ikev2Protocol::isFailedAuthError(QMap<time_t, QString> &logs)
|
|
||||||
{
|
|
||||||
for (QMap<time_t, QString>::iterator it = logs.begin(); it != logs.end(); ++it)
|
|
||||||
{
|
|
||||||
if (it.value().contains("Failed", Qt::CaseInsensitive) && it.value().contains("IKE", Qt::CaseInsensitive) && it.value().contains("Auth", Qt::CaseInsensitive))
|
|
||||||
{
|
|
||||||
if (!(it.value().contains("Failed", Qt::CaseInsensitive) && it.value().contains("IKEv2 socket", Qt::CaseInsensitive)))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Ikev2Protocol::isSocketError(QMap<time_t, QString> &logs)
|
|
||||||
{
|
|
||||||
for (QMap<time_t, QString>::iterator it = logs.begin(); it != logs.end(); ++it)
|
|
||||||
{
|
|
||||||
if (it.value().contains("Failed", Qt::CaseInsensitive) && it.value().contains("initialize", Qt::CaseInsensitive) && it.value().contains("socket", Qt::CaseInsensitive))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Ikev2Protocol::setCustomDns(const QString &overrideDnsIpAddress)
|
|
||||||
{
|
|
||||||
// get list of entries of interest
|
|
||||||
// QStringList networkServices = NetworkUtils_mac::getListOfDnsNetworkServiceEntries();
|
|
||||||
|
|
||||||
// filter list to only ikev2 entries
|
|
||||||
QStringList dnsNetworkServices;
|
|
||||||
// for (const QString &service : networkServices)
|
|
||||||
// if (MacUtils::dynamicStoreEntryHasKey(service, "ConfirmedServiceID"))
|
|
||||||
// dnsNetworkServices.append(service);
|
|
||||||
|
|
||||||
qDebug() << "Applying custom 'while connected' DNS change to network services: " << dnsNetworkServices;
|
|
||||||
|
|
||||||
if (dnsNetworkServices.isEmpty()) {
|
|
||||||
qDebug() << "No network services to configure 'while connected' DNS";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// change DNS on each entry
|
|
||||||
bool successAll = true;
|
|
||||||
for (const QString &service : dnsNetworkServices) {
|
|
||||||
// if (!helper_->setDnsOfDynamicStoreEntry(overrideDnsIpAddress, service)) {
|
|
||||||
// successAll = false;
|
|
||||||
// qDebug() << "Failed to set network service DNS: " << service;
|
|
||||||
// break;
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
|
|
||||||
return successAll;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue