Compare commits

...

19 Commits

Author SHA1 Message Date
Yaroslav Yashin ff589f47c2 Merge branch 'dev' into feature/awg-net-fix-macos-wakeup 2025-09-29 15:26:02 +03:00
Yaroslav Yashin f0ca9772d3 feat: implement SCP file upload without creating a temporary local file 2025-09-21 19:36:37 +03:00
AnhTVc 23b530a0f8 Merge branch 'dev' into feature/awg-net-fix-macos-wakeup
# Conflicts:
#	client/mozilla/localsocketcontroller.cpp
#	client/vpnconnection.cpp
#	ipc/ipcserver.cpp
#	service/server/localserver.cpp
2025-09-11 21:20:10 +07:00
AnhTVc 511b8fa6cc Fix macOS wakeup/sleep prob
Fix macOS not receiving wakeup/sleep events
2025-08-31 10:41:38 +07:00
Mykola Baibuz 38082f9940 Merge branch 'dev' into feature/awg-network-check 2025-04-08 20:52:48 +03:00
Mykola Baibuz 71691fa01e Add delay for Linux wakeup reconnect 2025-04-06 20:50:37 +03:00
Mykola Baibuz 62d9bcaf7f Add delay for Linux wakeup reconnect 2025-04-06 20:30:52 +03:00
Mykola Baibuz 5ef8254cba MacOS suspend mode handler draft 2025-04-03 22:12:54 +03:00
Mykola Baibuz f767171c06 Windows suspend mode handler 2025-04-03 20:45:27 +03:00
Mykola Baibuz eff460b227 Use ping check for tun interfce 2025-04-02 20:26:59 +03:00
Mykola Baibuz 319043818a Add DBus network checker for Linux 2025-04-02 11:33:15 +03:00
Mykola Baibuz e730521576 Restart IpcClient after OS suspend 2025-03-29 14:43:19 +02:00
Mykola Baibuz 517930dd22 handle for interafe problems on windows 2025-03-27 22:53:06 +02:00
Mykola Baibuz 26994c21b1 add delay for ping checker stop 2025-03-27 21:46:10 +02:00
Mykola Baibuz 681eb5aa86 fix android build 2025-03-27 21:28:14 +02:00
Mykola Baibuz 4b86425992 Use networkchecker for all protocols 2025-03-27 21:07:03 +02:00
Mykola Baibuz 9b41ed66bb Cleanup unused code 2025-03-26 21:11:40 +02:00
Mykola Baibuz 8bb4fa3f35 Use service for PingSender 2025-03-26 20:16:17 +02:00
Mykola Baibuz e792117be1 Add network status check for AWG/WG protocol 2025-03-12 23:32:00 +02:00
49 changed files with 10822 additions and 5859 deletions
+2 -2
View File
@@ -36,7 +36,6 @@ set(HEADERS ${HEADERS}
${CLIENT_ROOT_DIR}/mozilla/shared/ipaddress.h ${CLIENT_ROOT_DIR}/mozilla/shared/ipaddress.h
${CLIENT_ROOT_DIR}/mozilla/shared/leakdetector.h ${CLIENT_ROOT_DIR}/mozilla/shared/leakdetector.h
${CLIENT_ROOT_DIR}/mozilla/controllerimpl.h ${CLIENT_ROOT_DIR}/mozilla/controllerimpl.h
${CLIENT_ROOT_DIR}/mozilla/localsocketcontroller.h
) )
if(NOT IOS AND NOT MACOS_NE) if(NOT IOS AND NOT MACOS_NE)
@@ -86,7 +85,6 @@ set(SOURCES ${SOURCES}
${CLIENT_ROOT_DIR}/mozilla/models/server.cpp ${CLIENT_ROOT_DIR}/mozilla/models/server.cpp
${CLIENT_ROOT_DIR}/mozilla/shared/ipaddress.cpp ${CLIENT_ROOT_DIR}/mozilla/shared/ipaddress.cpp
${CLIENT_ROOT_DIR}/mozilla/shared/leakdetector.cpp ${CLIENT_ROOT_DIR}/mozilla/shared/leakdetector.cpp
${CLIENT_ROOT_DIR}/mozilla/localsocketcontroller.cpp
) )
if(NOT IOS AND NOT MACOS_NE) if(NOT IOS AND NOT MACOS_NE)
@@ -189,11 +187,13 @@ if(WIN32 OR (APPLE AND NOT IOS) OR (LINUX AND NOT ANDROID))
${CLIENT_ROOT_DIR}/protocols/wireguardprotocol.h ${CLIENT_ROOT_DIR}/protocols/wireguardprotocol.h
${CLIENT_ROOT_DIR}/protocols/xrayprotocol.h ${CLIENT_ROOT_DIR}/protocols/xrayprotocol.h
${CLIENT_ROOT_DIR}/protocols/awgprotocol.h ${CLIENT_ROOT_DIR}/protocols/awgprotocol.h
${CLIENT_ROOT_DIR}/mozilla/localsocketcontroller.h
) )
set(SOURCES ${SOURCES} set(SOURCES ${SOURCES}
${CLIENT_ROOT_DIR}/core/ipcclient.cpp ${CLIENT_ROOT_DIR}/core/ipcclient.cpp
${CLIENT_ROOT_DIR}/core/privileged_process.cpp ${CLIENT_ROOT_DIR}/core/privileged_process.cpp
${CLIENT_ROOT_DIR}/mozilla/localsocketcontroller.cpp
${CLIENT_ROOT_DIR}/ui/systemtray_notificationhandler.cpp ${CLIENT_ROOT_DIR}/ui/systemtray_notificationhandler.cpp
${CLIENT_ROOT_DIR}/protocols/openvpnprotocol.cpp ${CLIENT_ROOT_DIR}/protocols/openvpnprotocol.cpp
${CLIENT_ROOT_DIR}/protocols/openvpnovercloakprotocol.cpp ${CLIENT_ROOT_DIR}/protocols/openvpnovercloakprotocol.cpp
+2 -6
View File
@@ -197,12 +197,8 @@ ErrorCode ServerController::uploadFileToHost(const ServerCredentials &credential
return error; return error;
} }
QTemporaryFile localFile; // Write directly via SCP without creating a temporary local file.
localFile.open(); error = m_sshClient.scpWriteBuffer(overwriteMode, data, remotePath, "non_desc");
localFile.write(data);
localFile.close();
error = m_sshClient.scpFileCopy(overwriteMode, localFile.fileName(), remotePath, "non_desc");
if (error != ErrorCode::NoError) { if (error != ErrorCode::NoError) {
return error; return error;
+6
View File
@@ -18,6 +18,12 @@ bool IpcClient::isSocketConnected() const
return m_isSocketConnected; return m_isSocketConnected;
} }
void IpcClient::close()
{
if (m_localSocket)
m_localSocket->close();
}
IpcClient *IpcClient::Instance() IpcClient *IpcClient::Instance()
{ {
return m_instance; return m_instance;
+1
View File
@@ -23,6 +23,7 @@ public:
static QSharedPointer<PrivilegedProcess> CreatePrivilegedProcess(); static QSharedPointer<PrivilegedProcess> CreatePrivilegedProcess();
bool isSocketConnected() const; bool isSocketConnected() const;
void close();
signals: signals:
+49
View File
@@ -4,6 +4,7 @@
#include <QtConcurrent> #include <QtConcurrent>
#include <fstream> #include <fstream>
#include <algorithm>
#ifdef Q_OS_WINDOWS #ifdef Q_OS_WINDOWS
const uint32_t S_IRWXU = 0644; const uint32_t S_IRWXU = 0644;
@@ -290,6 +291,54 @@ namespace libssh {
return watcher.result(); return watcher.result();
} }
ErrorCode Client::scpWriteBuffer(const ScpOverwriteMode overwriteMode, const QByteArray &data, const QString &remotePath, const QString &fileDesc)
{
m_scpSession = ssh_scp_new(m_session, SSH_SCP_WRITE, remotePath.toStdString().c_str());
if (m_scpSession == nullptr) {
return fromLibsshErrorCode();
}
if (ssh_scp_init(m_scpSession) != SSH_OK) {
auto errorCode = fromLibsshErrorCode();
closeScpSession();
return errorCode;
}
QFutureWatcher<ErrorCode> watcher;
connect(&watcher, &QFutureWatcher<ErrorCode>::finished, this, &Client::scpWriteBufferFinished);
QFuture<ErrorCode> future = QtConcurrent::run([this, overwriteMode, &data, &remotePath, &fileDesc]() {
const int accessType = O_WRONLY | O_CREAT | overwriteMode;
const int totalSize = data.size();
int result = ssh_scp_push_file(m_scpSession, remotePath.toStdString().c_str(), totalSize, accessType);
if (result != SSH_OK) {
return fromLibsshErrorCode();
}
constexpr int bufferSize = 16384;
int transferred = 0;
while (transferred < totalSize) {
const int chunkSize = std::min(bufferSize, totalSize - transferred);
result = ssh_scp_write(m_scpSession, data.constData() + transferred, chunkSize);
if (result != SSH_OK) {
return fromLibsshErrorCode();
}
transferred += chunkSize;
}
return ErrorCode::NoError;
});
watcher.setFuture(future);
QEventLoop wait;
QObject::connect(this, &Client::scpWriteBufferFinished, &wait, &QEventLoop::quit);
wait.exec();
closeScpSession();
return watcher.result();
}
void Client::closeScpSession() void Client::closeScpSession()
{ {
if (m_scpSession != nullptr) { if (m_scpSession != nullptr) {
+6
View File
@@ -36,6 +36,11 @@ namespace libssh {
const QString &localPath, const QString &localPath,
const QString &remotePath, const QString &remotePath,
const QString &fileDesc); const QString &fileDesc);
// Copy data directly without a temporary local file
ErrorCode scpWriteBuffer(const ScpOverwriteMode overwriteMode,
const QByteArray &data,
const QString &remotePath,
const QString &fileDesc);
ErrorCode getDecryptedPrivateKey(const ServerCredentials &credentials, QString &decryptedPrivateKey, const std::function<QString()> &passphraseCallback); ErrorCode getDecryptedPrivateKey(const ServerCredentials &credentials, QString &decryptedPrivateKey, const std::function<QString()> &passphraseCallback);
private: private:
ErrorCode closeChannel(); ErrorCode closeChannel();
@@ -52,6 +57,7 @@ namespace libssh {
signals: signals:
void writeToChannelFinished(); void writeToChannelFinished();
void scpFileCopyFinished(); void scpFileCopyFinished();
void scpWriteBufferFinished();
}; };
} }
+1 -1
View File
@@ -8,7 +8,7 @@
#include <QList> #include <QList>
#include <QMap> #include <QMap>
#include <QString> #include <QString>
#include <QMap>
#include "ipaddress.h" #include "ipaddress.h"
class QJsonObject; class QJsonObject;
+16 -5
View File
@@ -5,6 +5,9 @@
#include <stdint.h> #include <stdint.h>
#include <QCoreApplication>
#include <QDateTime>
#include <QDebug>
#include <QDir> #include <QDir>
#include <QFileInfo> #include <QFileInfo>
#include <QHostAddress> #include <QHostAddress>
@@ -12,12 +15,13 @@
#include <QJsonDocument> #include <QJsonDocument>
#include <QJsonObject> #include <QJsonObject>
#include <QJsonValue> #include <QJsonValue>
#include <QLocalSocket>
#include <QObject>
#include <QStandardPaths> #include <QStandardPaths>
#include <QTimer>
#include "ipaddress.h"
#include "leakdetector.h" #include "leakdetector.h"
#include "logger.h" #include "logger.h"
#include "models/server.h"
#include "daemon/daemonerrors.h" #include "daemon/daemonerrors.h"
#include "protocols/protocols_defs.h" #include "protocols/protocols_defs.h"
@@ -115,7 +119,6 @@ void LocalSocketController::daemonConnected() {
} }
void LocalSocketController::activate(const QJsonObject &rawConfig) { void LocalSocketController::activate(const QJsonObject &rawConfig) {
QString protocolName = rawConfig.value("protocol").toString(); QString protocolName = rawConfig.value("protocol").toString();
int splitTunnelType = rawConfig.value("splitTunnelType").toInt(); int splitTunnelType = rawConfig.value("splitTunnelType").toInt();
@@ -132,13 +135,16 @@ void LocalSocketController::activate(const QJsonObject &rawConfig) {
// json.insert("hopindex", QJsonValue((double)hop.m_hopindex)); // json.insert("hopindex", QJsonValue((double)hop.m_hopindex));
json.insert("privateKey", wgConfig.value(amnezia::config_key::client_priv_key)); json.insert("privateKey", wgConfig.value(amnezia::config_key::client_priv_key));
json.insert("deviceIpv4Address", wgConfig.value(amnezia::config_key::client_ip)); json.insert("deviceIpv4Address", wgConfig.value(amnezia::config_key::client_ip));
m_deviceIpv4 = wgConfig.value(amnezia::config_key::client_ip).toString();
// set up IPv6 unique-local-address, ULA, with "fd00::/8" prefix, not globally routable. // set up IPv6 unique-local-address, ULA, with "fd00::/8" prefix, not globally routable.
// this will be default IPv6 gateway, OS recognizes that IPv6 link is local and switches to IPv4. // this will be default IPv6 gateway, OS recognizes that IPv6 link is local and switches to IPv4.
// Otherwise some OSes (Linux) try IPv6 forever and hang. // Otherwise some OSes (Linux) try IPv6 forever and hang.
// https://en.wikipedia.org/wiki/Unique_local_address (RFC 4193) // https://en.wikipedia.org/wiki/Unique_local_address (RFC 4193)
// https://man7.org/linux/man-pages/man5/gai.conf.5.html // https://man7.org/linux/man-pages/man5/gai.conf.5.html
json.insert("deviceIpv6Address", "fd58:baa6:dead::1"); // simply "dead::1" is globally-routable, don't use it
// simply "dead::1" is globally-routable, don't use it
json.insert("deviceIpv6Address", "fd58:baa6:dead::1");
json.insert("serverPublicKey", wgConfig.value(amnezia::config_key::server_pub_key)); json.insert("serverPublicKey", wgConfig.value(amnezia::config_key::server_pub_key));
json.insert("serverPskKey", wgConfig.value(amnezia::config_key::psk_key)); json.insert("serverPskKey", wgConfig.value(amnezia::config_key::psk_key));
@@ -220,7 +226,6 @@ void LocalSocketController::activate(const QJsonObject &rawConfig) {
json.insert("allowedIPAddressRanges", jsAllowedIPAddesses); json.insert("allowedIPAddressRanges", jsAllowedIPAddesses);
QJsonArray jsExcludedAddresses; QJsonArray jsExcludedAddresses;
jsExcludedAddresses.append(wgConfig.value(amnezia::config_key::hostName)); jsExcludedAddresses.append(wgConfig.value(amnezia::config_key::hostName));
if (splitTunnelType == 2) { if (splitTunnelType == 2) {
@@ -449,6 +454,7 @@ void LocalSocketController::parseCommand(const QByteArray& command) {
} }
if (type == "status") { if (type == "status") {
QJsonValue serverIpv4Gateway = obj.value("serverIpv4Gateway"); QJsonValue serverIpv4Gateway = obj.value("serverIpv4Gateway");
if (!serverIpv4Gateway.isString()) { if (!serverIpv4Gateway.isString()) {
logger.error() << "Unexpected serverIpv4Gateway value"; logger.error() << "Unexpected serverIpv4Gateway value";
@@ -493,6 +499,11 @@ void LocalSocketController::parseCommand(const QByteArray& command) {
logger.debug() << "Handshake completed with:" logger.debug() << "Handshake completed with:"
<< pubkey.toString(); << pubkey.toString();
checkStatus();
emit statusUpdated("", m_deviceIpv4, 0, 0);
emit connected(pubkey.toString()); emit connected(pubkey.toString());
return; return;
} }
+2
View File
@@ -12,6 +12,7 @@
#include "controllerimpl.h" #include "controllerimpl.h"
class QJsonObject; class QJsonObject;
class LocalSocketController final : public ControllerImpl { class LocalSocketController final : public ControllerImpl {
@@ -58,6 +59,7 @@ class LocalSocketController final : public ControllerImpl {
QByteArray m_buffer; QByteArray m_buffer;
QString m_deviceIpv4;
std::function<void(const QString&)> m_logCallback = nullptr; std::function<void(const QString&)> m_logCallback = nullptr;
QTimer m_initializingTimer; QTimer m_initializingTimer;
+22 -37
View File
@@ -11,7 +11,6 @@
#include "logger.h" #include "logger.h"
//#include "mozillavpn.h" //#include "mozillavpn.h"
#include "networkwatcherimpl.h" #include "networkwatcherimpl.h"
#include "platforms/dummy/dummynetworkwatcher.h"
//#include "settingsholder.h" //#include "settingsholder.h"
#ifdef MZ_WINDOWS #ifdef MZ_WINDOWS
@@ -51,7 +50,7 @@ NetworkWatcher::NetworkWatcher() { MZ_COUNT_CTOR(NetworkWatcher); }
NetworkWatcher::~NetworkWatcher() { MZ_COUNT_DTOR(NetworkWatcher); } NetworkWatcher::~NetworkWatcher() { MZ_COUNT_DTOR(NetworkWatcher); }
void NetworkWatcher::initialize() { void NetworkWatcher::initialize() {
logger.debug() << "Initialize"; logger.debug() << "Initialize NetworkWatcher";
#if defined(MZ_WINDOWS) #if defined(MZ_WINDOWS)
m_impl = new WindowsNetworkWatcher(this); m_impl = new WindowsNetworkWatcher(this);
@@ -69,59 +68,45 @@ void NetworkWatcher::initialize() {
m_impl = new DummyNetworkWatcher(this); m_impl = new DummyNetworkWatcher(this);
#endif #endif
connect(m_impl, &NetworkWatcherImpl::unsecuredNetwork, this, connect(m_impl, &NetworkWatcherImpl::unsecuredNetwork, this,
&NetworkWatcher::unsecuredNetwork); &NetworkWatcher::unsecuredNetwork);
connect(m_impl, &NetworkWatcherImpl::networkChanged, this, connect(m_impl, &NetworkWatcherImpl::networkChanged, this,
&NetworkWatcher::networkChange); &NetworkWatcher::networkChange);
connect(m_impl, &NetworkWatcherImpl::sleepMode, this,
&NetworkWatcher::onSleepMode);
m_impl->initialize(); m_impl->initialize();
// Enable sleep/wake monitoring for VPN auto-reconnection
// TODO: IMPL FOR AMNEZIA logger.debug() << "Starting NetworkWatcher for sleep/wake monitoring";
#if 0 logger.debug() << "About to call m_impl->start()";
SettingsHolder* settingsHolder = SettingsHolder::instance(); try {
Q_ASSERT(settingsHolder);
m_active = settingsHolder->unsecuredNetworkAlert() ||
settingsHolder->captivePortalAlert();
m_reportUnsecuredNetwork = settingsHolder->unsecuredNetworkAlert();
if (m_active) {
m_impl->start(); m_impl->start();
logger.debug() << "m_impl->start() completed successfully";
} catch (const std::exception& e) {
logger.error() << "Exception in m_impl->start():" << e.what();
} catch (...) {
logger.error() << "Unknown exception in m_impl->start()";
} }
m_active = true;
connect(settingsHolder, &SettingsHolder::unsecuredNetworkAlertChanged, this, m_reportUnsecuredNetwork = false; // Disable unsecured network alerts for Amnezia
&NetworkWatcher::settingsChanged);
connect(settingsHolder, &SettingsHolder::captivePortalAlertChanged, this,
&NetworkWatcher::settingsChanged);
#endif
} }
void NetworkWatcher::settingsChanged() { void NetworkWatcher::settingsChanged() {
// TODO: IMPL FOR AMNEZIA // For Amnezia: Keep NetworkWatcher always active for sleep/wake monitoring
#if 0 logger.debug() << "NetworkWatcher settings changed - keeping sleep monitoring active";
SettingsHolder* settingsHolder = SettingsHolder::instance(); }
m_active = settingsHolder->unsecuredNetworkAlert() ||
settingsHolder->captivePortalAlert();
m_reportUnsecuredNetwork = settingsHolder->unsecuredNetworkAlert();
if (m_active) { void NetworkWatcher::onSleepMode()
logger.debug() {
<< "Starting Network Watcher; Reporting of Unsecured Networks: " logger.debug() << "Resumed from sleep mode";
<< m_reportUnsecuredNetwork; emit sleepMode();
m_impl->start();
} else {
logger.debug() << "Stopping Network Watcher";
m_impl->stop();
}
#endif
} }
void NetworkWatcher::unsecuredNetwork(const QString& networkName, void NetworkWatcher::unsecuredNetwork(const QString& networkName,
const QString& networkId) { const QString& networkId) {
logger.debug() << "Unsecured network:" << logger.sensitive(networkName) logger.debug() << "Unsecured network:" << logger.sensitive(networkName)
<< "id:" << logger.sensitive(networkId); << "id:" << logger.sensitive(networkId);
#ifndef UNIT_TEST #ifndef UNIT_TEST
if (!m_reportUnsecuredNetwork) { if (!m_reportUnsecuredNetwork) {
logger.debug() << "Disabled. Ignoring unsecured network"; logger.debug() << "Disabled. Ignoring unsecured network";
+3
View File
@@ -29,10 +29,13 @@ public:
// false to restore. // false to restore.
void simulateDisconnection(bool simulatedDisconnection); void simulateDisconnection(bool simulatedDisconnection);
void onSleepMode();
QNetworkInformation::Reachability getReachability(); QNetworkInformation::Reachability getReachability();
signals: signals:
void networkChange(); void networkChange();
void sleepMode();
private: private:
void settingsChanged(); void settingsChanged();
+2
View File
@@ -41,6 +41,8 @@ signals:
// TODO: Only windows-networkwatcher has this, the other plattforms should // TODO: Only windows-networkwatcher has this, the other plattforms should
// too. // too.
void networkChanged(QString newBSSID); void networkChanged(QString newBSSID);
void sleepMode();
private: private:
bool m_active = false; bool m_active = false;
+5 -2
View File
@@ -41,6 +41,7 @@ void PingHelper::start(const QString& serverIpv4Gateway,
m_gateway = QHostAddress(serverIpv4Gateway); m_gateway = QHostAddress(serverIpv4Gateway);
m_source = QHostAddress(deviceIpv4Address.section('/', 0, 0)); m_source = QHostAddress(deviceIpv4Address.section('/', 0, 0));
m_pingSender = PingSenderFactory::create(m_source, this); m_pingSender = PingSenderFactory::create(m_source, this);
// Some platforms require root access to send and receive ICMP pings. If // Some platforms require root access to send and receive ICMP pings. If
@@ -53,8 +54,10 @@ void PingHelper::start(const QString& serverIpv4Gateway,
connect(m_pingSender, &PingSender::recvPing, this, &PingHelper::pingReceived, connect(m_pingSender, &PingSender::recvPing, this, &PingHelper::pingReceived,
Qt::QueuedConnection); Qt::QueuedConnection);
connect(m_pingSender, &PingSender::criticalPingError, this, connect(m_pingSender, &PingSender::criticalPingError, this, [this]() {
[]() { logger.info() << "Encountered Unrecoverable ping error"; }); logger.info() << "Encountered Unrecoverable ping error";
emit connectionLose();
});
// Reset the ping statistics // Reset the ping statistics
m_sequence = 0; m_sequence = 0;
+2
View File
@@ -33,6 +33,8 @@ class PingHelper final : public QObject {
signals: signals:
void pingSentAndReceived(qint64 msec); void pingSentAndReceived(qint64 msec);
void connectionLose();
private: private:
void nextPing(); void nextPing();
+10 -11
View File
@@ -5,27 +5,26 @@
#include "pingsenderfactory.h" #include "pingsenderfactory.h"
#if defined(MZ_LINUX) || defined(MZ_ANDROID) #if defined(MZ_LINUX) || defined(MZ_ANDROID)
//# include "platforms/linux/linuxpingsender.h" # include "platforms/linux/linuxpingsender.h"
#elif defined(MZ_MACOS) || defined(MZ_IOS) #elif defined(MZ_MACOS) || defined(MZ_IOS)
# include "platforms/macos/macospingsender.h" # include "platforms/macos/macospingsender.h"
#elif defined(MZ_WINDOWS) #elif defined(MZ_WINDOWS)
# include "platforms/windows/windowspingsender.h" # include "platforms/windows/windowspingsender.h"
#elif defined(MZ_DUMMY) || defined(UNIT_TEST) #elif defined(MZ_WASM) || defined(UNIT_TEST)
# include "platforms/dummy/dummypingsender.h" # include "platforms/dummy/dummypingsender.h"
#else #else
# error "Unsupported platform" # error "Unsupported platform"
#endif #endif
PingSender* PingSenderFactory::create(const QHostAddress& source, PingSender* PingSenderFactory::create(const QHostAddress& source,
QObject* parent) { QObject* parent) {
#if defined(MZ_LINUX) || defined(MZ_ANDROID) #if defined(MZ_LINUX) || defined(MZ_ANDROID)
return nullptr; return new LinuxPingSender(source, parent);
// return new LinuxPingSender(source, parent);
#elif defined(MZ_MACOS) || defined(MZ_IOS) #elif defined(MZ_MACOS) || defined(MZ_IOS)
return new MacOSPingSender(source, parent); return new MacOSPingSender(source, parent);
#elif defined(MZ_WINDOWS) #elif defined(MZ_WINDOWS)
return new WindowsPingSender(source, parent); return new WindowsPingSender(source, parent);
#else #else
return new DummyPingSender(source, parent); return new DummyPingSender(source, parent);
#endif #endif
} }
+4 -3
View File
@@ -10,9 +10,10 @@ class QHostAddress;
class QObject; class QObject;
class PingSenderFactory final { class PingSenderFactory final {
public: public:
PingSenderFactory() = delete; PingSenderFactory() = delete;
static PingSender* create(const QHostAddress& source, QObject* parent); static PingSender* create(const QHostAddress& source, QObject* parent);
}; };
#endif // PINGSENDERFACTORY_H #endif // PINGSENDERFACTORY_H
@@ -34,6 +34,9 @@ void IOSNetworkWatcher::initialize() {
}); });
nw_path_monitor_start(m_networkMonitor); nw_path_monitor_start(m_networkMonitor);
// Call start() to initialize sleep/wake monitoring (will call MacOSNetworkWatcher::start() if this is macOS)
this->start();
//TODO IMPL FOR AMNEZIA //TODO IMPL FOR AMNEZIA
} }
@@ -41,6 +41,9 @@ void LinuxNetworkWatcher::initialize() {
connect(m_worker, &LinuxNetworkWatcherWorker::unsecuredNetwork, this, connect(m_worker, &LinuxNetworkWatcherWorker::unsecuredNetwork, this,
&LinuxNetworkWatcher::unsecuredNetwork); &LinuxNetworkWatcher::unsecuredNetwork);
connect(m_worker, &LinuxNetworkWatcherWorker::sleepMode, this,
&NetworkWatcherImpl::sleepMode);
// Let's wait a few seconds to allow the UI to be fully loaded and shown. // Let's wait a few seconds to allow the UI to be fully loaded and shown.
// This is not strictly needed, but it's better for user experience because // This is not strictly needed, but it's better for user experience because
// it makes the UI faster to appear, plus it gives a bit of delay between the // it makes the UI faster to appear, plus it gives a bit of delay between the
@@ -33,7 +33,21 @@
#define NM_802_11_AP_SEC_WEAK_CRYPTO \ #define NM_802_11_AP_SEC_WEAK_CRYPTO \
(NM_802_11_AP_SEC_PAIR_WEP40 | NM_802_11_AP_SEC_PAIR_WEP104) (NM_802_11_AP_SEC_PAIR_WEP40 | NM_802_11_AP_SEC_PAIR_WEP104)
enum NMState {
NM_STATE_UNKNOWN = 0,
NM_STATE_ASLEEP = 10,
NM_STATE_DISCONNECTED = 20,
NM_STATE_DISCONNECTING = 30,
NM_STATE_CONNECTING = 40,
NM_STATE_CONNECTED_LOCAL = 50,
NM_STATE_CONNECTED_SITE = 60,
NM_STATE_CONNECTED_GLOBAL = 70
};
constexpr const char* DBUS_NETWORKMANAGER = "org.freedesktop.NetworkManager"; constexpr const char* DBUS_NETWORKMANAGER = "org.freedesktop.NetworkManager";
constexpr const char* DBUS_NETWORKMANAGER_PATH = "/org/freedesktop/NetworkManager";
namespace { namespace {
Logger logger("LinuxNetworkWatcherWorker"); Logger logger("LinuxNetworkWatcherWorker");
@@ -73,7 +87,7 @@ void LinuxNetworkWatcherWorker::initialize() {
// documentation: // documentation:
// https://developer.gnome.org/NetworkManager/stable/gdbus-org.freedesktop.NetworkManager.html // https://developer.gnome.org/NetworkManager/stable/gdbus-org.freedesktop.NetworkManager.html
QDBusInterface nm(DBUS_NETWORKMANAGER, "/org/freedesktop/NetworkManager", QDBusInterface nm(DBUS_NETWORKMANAGER, DBUS_NETWORKMANAGER_PATH,
DBUS_NETWORKMANAGER, QDBusConnection::systemBus()); DBUS_NETWORKMANAGER, QDBusConnection::systemBus());
if (!nm.isValid()) { if (!nm.isValid()) {
logger.error() logger.error()
@@ -108,6 +122,12 @@ void LinuxNetworkWatcherWorker::initialize() {
SLOT(propertyChanged(QString, QVariantMap, QStringList))); SLOT(propertyChanged(QString, QVariantMap, QStringList)));
} }
QDBusConnection::systemBus().connect(DBUS_NETWORKMANAGER,
DBUS_NETWORKMANAGER_PATH,
DBUS_NETWORKMANAGER,
"StateChanged",
this, SLOT(NMStateChanged(quint32)));
if (m_devicePaths.isEmpty()) { if (m_devicePaths.isEmpty()) {
logger.warning() << "No wifi devices found"; logger.warning() << "No wifi devices found";
return; return;
@@ -173,5 +193,16 @@ void LinuxNetworkWatcherWorker::checkDevices() {
emit unsecuredNetwork(ssid, bssid); emit unsecuredNetwork(ssid, bssid);
break; break;
} }
} }
} }
void LinuxNetworkWatcherWorker::NMStateChanged(quint32 state)
{
if (state == NM_STATE_ASLEEP) {
emit sleepMode();
}
logger.debug() << "NMStateChanged " << state;
}
@@ -23,6 +23,7 @@ class LinuxNetworkWatcherWorker final : public QObject {
signals: signals:
void unsecuredNetwork(const QString& networkName, const QString& networkId); void unsecuredNetwork(const QString& networkName, const QString& networkId);
void sleepMode();
public slots: public slots:
void initialize(); void initialize();
@@ -30,6 +31,7 @@ class LinuxNetworkWatcherWorker final : public QObject {
private slots: private slots:
void propertyChanged(QString interface, QVariantMap properties, void propertyChanged(QString interface, QVariantMap properties,
QStringList list); QStringList list);
void NMStateChanged(quint32 state);
private: private:
// We collect the list of DBus wifi network device paths during the // We collect the list of DBus wifi network device paths during the
+185
View File
@@ -0,0 +1,185 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "linuxpingsender.h"
#include <arpa/inet.h>
#include <errno.h>
#include <linux/filter.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
#include <sys/socket.h>
#include <unistd.h>
#include <QSocketNotifier>
#include <QtEndian>
#include "leakdetector.h"
#include "logger.h"
#include "qhostaddress.h"
namespace {
Logger logger("LinuxPingSender");
}
int LinuxPingSender::createSocket() {
// Try creating an ICMP socket. This would be the ideal choice, but it can
// fail depending on the kernel config (see: sys.net.ipv4.ping_group_range)
m_socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_ICMP);
if (m_socket >= 0) {
m_ident = 0;
return m_socket;
}
if ((errno != EPERM) && (errno != EACCES)) {
return -1;
}
// As a fallback, create a raw socket, which requires root permissions
// or CAP_NET_RAW to be granted to the VPN client.
m_socket = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
if (m_socket < 0) {
return -1;
}
m_ident = getpid() & 0xffff;
// Attach a BPF filter to discard everything but replies to our echo.
struct sock_filter bpf_prog[] = {
BPF_STMT(BPF_LDX | BPF_B | BPF_MSH, 0), /* Skip IP header. */
BPF_STMT(BPF_LD | BPF_H | BPF_IND, 4), /* Load icmp echo ident */
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, m_ident, 1, 0), /* Ours? */
BPF_STMT(BPF_RET | BPF_K, 0), /* Unexpected identifier. Reject. */
BPF_STMT(BPF_LD | BPF_B | BPF_IND, 0), /* Load icmp type */
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, ICMP_ECHOREPLY, 1, 0), /* Echo? */
BPF_STMT(BPF_RET | BPF_K, 0), /* Unexpected type. Reject. */
BPF_STMT(BPF_RET | BPF_K, ~0U), /* Packet passes the filter. */
};
struct sock_fprog filter = {
.len = sizeof(bpf_prog) / sizeof(struct sock_filter),
.filter = bpf_prog,
};
setsockopt(m_socket, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter));
return m_socket;
}
LinuxPingSender::LinuxPingSender(const QHostAddress& source, QObject* parent)
: PingSender(parent) {
MZ_COUNT_CTOR(LinuxPingSender);
logger.debug() << "LinuxPingSender(" + logger.sensitive(source.toString()) +
") created";
m_socket = createSocket();
if (m_socket < 0) {
logger.error() << "Socket creation error: " << strerror(errno);
return;
}
quint32 ipv4addr = INADDR_ANY;
if (!source.isNull()) {
ipv4addr = source.toIPv4Address();
}
struct sockaddr_in addr;
memset(&addr, 0, sizeof addr);
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = qToBigEndian<quint32>(ipv4addr);
if (bind(m_socket, (struct sockaddr*)&addr, sizeof(addr)) != 0) {
close(m_socket);
m_socket = -1;
logger.error() << "bind error:" << strerror(errno);
return;
}
m_notifier = new QSocketNotifier(m_socket, QSocketNotifier::Read, this);
if (m_ident) {
connect(m_notifier, &QSocketNotifier::activated, this,
&LinuxPingSender::rawSocketReady);
} else {
connect(m_notifier, &QSocketNotifier::activated, this,
&LinuxPingSender::icmpSocketReady);
}
}
LinuxPingSender::~LinuxPingSender() {
MZ_COUNT_DTOR(LinuxPingSender);
if (m_socket >= 0) {
close(m_socket);
}
}
void LinuxPingSender::sendPing(const QHostAddress& dest, quint16 sequence) {
quint32 ipv4dest = dest.toIPv4Address();
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = qToBigEndian<quint32>(ipv4dest);
struct icmphdr packet;
memset(&packet, 0, sizeof(packet));
packet.type = ICMP_ECHO;
packet.un.echo.id = htons(m_ident);
packet.un.echo.sequence = htons(sequence);
packet.checksum = inetChecksum(&packet, sizeof(packet));
int rc = sendto(m_socket, &packet, sizeof(packet), 0, (struct sockaddr*)&addr,
sizeof(addr));
if (rc < 0) {
logger.error() << "failed to send:" << strerror(errno);
if (errno == ENETUNREACH) {
emit criticalPingError();
}
}
}
void LinuxPingSender::icmpSocketReady() {
socklen_t slen = 0;
unsigned char data[2048];
int rc = recvfrom(m_socket, data, sizeof(data), MSG_DONTWAIT, NULL, &slen);
if (rc <= 0) {
logger.error() << "recvfrom failed:" << strerror(errno);
return;
}
struct icmphdr packet;
if (rc >= (int)sizeof(packet)) {
memcpy(&packet, data, sizeof(packet));
if (packet.type == ICMP_ECHOREPLY) {
emit recvPing(htons(packet.un.echo.sequence));
}
}
}
void LinuxPingSender::rawSocketReady() {
socklen_t slen = 0;
unsigned char data[2048];
int rc = recvfrom(m_socket, data, sizeof(data), MSG_DONTWAIT, NULL, &slen);
if (rc <= 0) {
logger.error() << "recvfrom failed:" << strerror(errno);
return;
}
// Check the IP header
const struct iphdr* ip = (struct iphdr*)data;
int iphdrlen = ip->ihl * 4;
if (rc < iphdrlen || iphdrlen < (int)sizeof(struct iphdr)) {
logger.error() << "malformed IP packet:" << strerror(errno);
return;
}
// Check the ICMP packet
struct icmphdr packet;
if (inetChecksum(data + iphdrlen, rc - iphdrlen) != 0) {
logger.warning() << "invalid checksum";
return;
}
if (rc >= (iphdrlen + (int)sizeof(packet))) {
memcpy(&packet, data + iphdrlen, sizeof(packet));
quint16 id = htons(m_ident);
if ((packet.type == ICMP_ECHOREPLY) && (packet.un.echo.id == id)) {
emit recvPing(htons(packet.un.echo.sequence));
}
}
}
+39
View File
@@ -0,0 +1,39 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef LINUXPINGSENDER_H
#define LINUXPINGSENDER_H
#include <QObject>
#include "../client/mozilla/pingsender.h"
class QSocketNotifier;
class LinuxPingSender final : public PingSender {
Q_OBJECT
Q_DISABLE_COPY_MOVE(LinuxPingSender)
public:
LinuxPingSender(const QHostAddress& source, QObject* parent = nullptr);
~LinuxPingSender();
bool isValid() override { return (m_socket >= 0); };
void sendPing(const QHostAddress& dest, quint16 sequence) override;
private:
int createSocket();
private slots:
void rawSocketReady();
void icmpSocketReady();
private:
QSocketNotifier* m_notifier = nullptr;
int m_socket = -1;
quint16 m_ident = 0;
};
#endif // LINUXPINGSENDER_H
@@ -10,8 +10,31 @@
#include "../ios/iosnetworkwatcher.h" #include "../ios/iosnetworkwatcher.h"
#include "networkwatcherimpl.h" #include "networkwatcherimpl.h"
#include <IOKit/pwr_mgt/IOPMLib.h>
#include <IOKit/IOMessage.h>
class QString; class QString;
// Inspired by https://ladydebug.com/blog/2020/05/21/programmatically-capture-energy-saver-event-on-mac/
class PowerNotificationsListener
{
public:
PowerNotificationsListener(class MacOSNetworkWatcher* watcher) : m_watcher(watcher) {}
void registerForNotifications();
void cleanup();
private:
static void sleepWakeupCallBack(void *refParam, io_service_t service, natural_t messageType, void *messageArgument);
private:
class MacOSNetworkWatcher* m_watcher = nullptr;
IONotificationPortRef notifyPortRef = nullptr; // notification port allocated by IORegisterForSystemPower
io_object_t notifierObj = IO_OBJECT_NULL; // notifier object, used to deregister later
io_connect_t rootPowerDomain = IO_OBJECT_NULL; // a reference to the Root Power Domain IOService
};
class MacOSNetworkWatcher final : public IOSNetworkWatcher { class MacOSNetworkWatcher final : public IOSNetworkWatcher {
public: public:
MacOSNetworkWatcher(QObject* parent); MacOSNetworkWatcher(QObject* parent);
@@ -25,6 +48,7 @@ class MacOSNetworkWatcher final : public IOSNetworkWatcher {
private: private:
void* m_delegate = nullptr; void* m_delegate = nullptr;
PowerNotificationsListener m_powerlistener;
}; };
#endif // MACOSNETWORKWATCHER_H #endif // MACOSNETWORKWATCHER_H
+240 -34
View File
@@ -6,6 +6,11 @@
#include "leakdetector.h" #include "leakdetector.h"
#include "logger.h" #include "logger.h"
#include <QProcess>
#include <QMetaObject>
#include <pthread.h>
#include <iostream>
#import <CoreWLAN/CoreWLAN.h> #import <CoreWLAN/CoreWLAN.h>
#import <Network/Network.h> #import <Network/Network.h>
@@ -13,6 +18,37 @@ namespace {
Logger logger("MacOSNetworkWatcher"); Logger logger("MacOSNetworkWatcher");
} }
// Global variables for CFRunLoop thread
static pthread_t g_powerThread;
static CFRunLoopRef g_powerRunLoop = nullptr;
static bool g_shouldStopPowerThread = false;
static PowerNotificationsListener* g_powerListener = nullptr;
// Thread function for dedicated CFRunLoop
void* powerMonitoringThread(void* arg) {
logger.debug() << "Power monitoring thread started";
PowerNotificationsListener* listener = static_cast<PowerNotificationsListener*>(arg);
// Get the runloop for this thread
g_powerRunLoop = CFRunLoopGetCurrent();
// Register for power notifications in this thread
listener->registerForNotifications();
// Run the CFRunLoop - this will block until CFRunLoopStop is called
while (!g_shouldStopPowerThread) {
CFRunLoopRunInMode(kCFRunLoopDefaultMode, 1.0, true);
}
// Cleanup
listener->cleanup();
g_powerRunLoop = nullptr;
logger.debug() << "Power monitoring thread finished";
return nullptr;
}
@interface MacOSNetworkWatcherDelegate : NSObject <CWEventDelegate> { @interface MacOSNetworkWatcherDelegate : NSObject <CWEventDelegate> {
MacOSNetworkWatcher* m_watcher; MacOSNetworkWatcher* m_watcher;
} }
@@ -38,12 +74,138 @@ Logger logger("MacOSNetworkWatcher");
@end @end
MacOSNetworkWatcher::MacOSNetworkWatcher(QObject* parent) : IOSNetworkWatcher(parent) { void PowerNotificationsListener::registerForNotifications()
{
logger.debug() << "Registering for system power notifications in dedicated thread";
rootPowerDomain = IORegisterForSystemPower(this, &notifyPortRef, sleepWakeupCallBack, &notifierObj);
if (rootPowerDomain == IO_OBJECT_NULL) {
logger.error() << "Failed to register for system power notifications!";
return;
}
// Add the notification port to the current runloop (dedicated thread)
CFRunLoopAddSource(CFRunLoopGetCurrent(), IONotificationPortGetRunLoopSource(notifyPortRef), kCFRunLoopCommonModes);
logger.debug() << "Power notifications registered successfully";
}
void PowerNotificationsListener::cleanup()
{
if (notifyPortRef != nullptr) {
CFRunLoopRemoveSource(CFRunLoopGetCurrent(), IONotificationPortGetRunLoopSource(notifyPortRef), kCFRunLoopCommonModes);
IONotificationPortDestroy(notifyPortRef);
notifyPortRef = nullptr;
}
if (notifierObj != IO_OBJECT_NULL) {
IODeregisterForSystemPower(&notifierObj);
notifierObj = IO_OBJECT_NULL;
}
if (rootPowerDomain != IO_OBJECT_NULL) {
IOServiceClose(rootPowerDomain);
rootPowerDomain = IO_OBJECT_NULL;
}
}
void PowerNotificationsListener::sleepWakeupCallBack(void *refParam, io_service_t service, natural_t messageType, void *messageArgument)
{
Q_UNUSED(service)
auto listener = static_cast<PowerNotificationsListener *>(refParam);
logger.debug() << "Power callback received, messageType:" << messageType;
switch (messageType) {
case kIOMessageCanSystemSleep:
/* Idle sleep is about to kick in. This message will not be sent for forced sleep.
* Applications have a chance to prevent sleep by calling IOCancelPowerChange.
* Most applications should not prevent idle sleep. Power Management waits up to
* 30 seconds for you to either allow or deny idle sleep. If you dont acknowledge
* this power change by calling either IOAllowPowerChange or IOCancelPowerChange,
* the system will wait 30 seconds then go to sleep.
*/
logger.debug() << "System power message: can system sleep?";
// Uncomment to cancel idle sleep
// IOCancelPowerChange(thiz->rootPowerDomain, reinterpret_cast<long>(messageArgument));
// Allow idle sleep
IOAllowPowerChange(listener->rootPowerDomain, reinterpret_cast<long>(messageArgument));
break;
case kIOMessageSystemWillNotSleep:
/* Announces that the system has retracted a previous attempt to sleep; it
* follows `kIOMessageCanSystemSleep`.
*/
logger.debug() << "System power message: system will NOT sleep.";
break;
case kIOMessageSystemWillSleep:
/* The system WILL go to sleep. If you do not call IOAllowPowerChange or
* IOCancelPowerChange to acknowledge this message, sleep will be delayed by
* 30 seconds.
*
* NOTE: If you call IOCancelPowerChange to deny sleep it returns kIOReturnSuccess,
* however the system WILL still go to sleep.
*/
logger.debug() << "System power message: system WILL sleep";
IOAllowPowerChange(listener->rootPowerDomain, reinterpret_cast<long>(messageArgument));
break;
case kIOMessageSystemWillPowerOn:
/* Announces that the system is beginning to power the device tree; most devices
* are still unavailable at this point.
*/
/* From the documentation:
*
* - kIOMessageSystemWillPowerOn is delivered at early wakeup time, before most hardware
* has been powered on. Be aware that any attempts to access disk, network, the display,
* etc. may result in errors or blocking your process until those resources become
* available.
*
* So we do NOT log this event.
*/
break;
case kIOMessageSystemHasPoweredOn:
/* Announces that the system and its devices have woken up. */
logger.debug() << "System has powered on - emitting sleepMode signal from dedicated CFRunLoop thread";
if (listener->m_watcher) {
// Use QMetaObject::invokeMethod for thread-safe signal emission
QMetaObject::invokeMethod(listener->m_watcher, "sleepMode", Qt::QueuedConnection);
}
break;
default:
logger.debug() << "System power message: other event: " << messageType;
/* Not a system sleep and wake notification. */
break;
}
}
MacOSNetworkWatcher::MacOSNetworkWatcher(QObject* parent) : IOSNetworkWatcher(parent), m_powerlistener(this) {
MZ_COUNT_CTOR(MacOSNetworkWatcher); MZ_COUNT_CTOR(MacOSNetworkWatcher);
} }
MacOSNetworkWatcher::~MacOSNetworkWatcher() { MacOSNetworkWatcher::~MacOSNetworkWatcher() {
MZ_COUNT_DTOR(MacOSNetworkWatcher); MZ_COUNT_DTOR(MacOSNetworkWatcher);
// Stop the dedicated power monitoring thread
if (g_powerListener) {
logger.debug() << "Stopping dedicated power monitoring thread";
g_shouldStopPowerThread = true;
if (g_powerRunLoop) {
CFRunLoopStop(g_powerRunLoop);
}
// Wait for thread to finish
pthread_join(g_powerThread, nullptr);
g_powerListener = nullptr;
}
if (m_delegate) { if (m_delegate) {
CWWiFiClient* client = CWWiFiClient.sharedWiFiClient; CWWiFiClient* client = CWWiFiClient.sharedWiFiClient;
if (!client) { if (!client) {
@@ -66,6 +228,20 @@ void MacOSNetworkWatcher::start() {
logger.debug() << "Delegate already registered"; logger.debug() << "Delegate already registered";
return; return;
} }
// Start dedicated power monitoring thread with CFRunLoop
if (!g_powerListener) {
g_powerListener = &m_powerlistener;
g_shouldStopPowerThread = false;
int result = pthread_create(&g_powerThread, nullptr, powerMonitoringThread, &m_powerlistener);
if (result != 0) {
logger.error() << "Failed to create power monitoring thread:" << result;
g_powerListener = nullptr;
} else {
logger.debug() << "Power monitoring enabled";
}
}
CWWiFiClient* client = CWWiFiClient.sharedWiFiClient; CWWiFiClient* client = CWWiFiClient.sharedWiFiClient;
if (!client) { if (!client) {
@@ -77,6 +253,8 @@ void MacOSNetworkWatcher::start() {
m_delegate = [[MacOSNetworkWatcherDelegate alloc] initWithObject:this]; m_delegate = [[MacOSNetworkWatcherDelegate alloc] initWithObject:this];
[client setDelegate:static_cast<MacOSNetworkWatcherDelegate*>(m_delegate)]; [client setDelegate:static_cast<MacOSNetworkWatcherDelegate*>(m_delegate)];
[client startMonitoringEventWithType:CWEventTypeBSSIDDidChange error:nullptr]; [client startMonitoringEventWithType:CWEventTypeBSSIDDidChange error:nullptr];
logger.debug() << "MacOSNetworkWatcher started successfully";
} }
void MacOSNetworkWatcher::checkInterface() { void MacOSNetworkWatcher::checkInterface() {
@@ -87,42 +265,70 @@ void MacOSNetworkWatcher::checkInterface() {
return; return;
} }
CWWiFiClient* client = CWWiFiClient.sharedWiFiClient; // Use wdutil to get reliable WiFi information
if (!client) { QProcess process;
logger.debug() << "Unable to retrieve the CWWiFiClient shared instance"; process.start("wdutil", QStringList() << "info");
process.waitForFinished(5000);
QString output = process.readAllStandardOutput();
QString errorOutput = process.readAllStandardError();
logger.debug() << "wdutil exit code:" << process.exitCode();
if (process.exitCode() != 0) {
logger.debug() << "wdutil failed with exit code:" << process.exitCode();
return; return;
} }
CWInterface* interface = [client interface]; // Parse wdutil output to find WiFi connection info
if (!interface) { QStringList lines = output.split('\n');
logger.debug() << "No default wifi interface"; QString ssid, interfaceName, security;
return; bool wifiSectionFound = false;
for (int i = 0; i < lines.size(); i++) {
QString trimmedLine = lines[i].trimmed();
if (trimmedLine == "WIFI") {
wifiSectionFound = true;
continue;
}
if (wifiSectionFound) {
// Stop parsing when we reach next section header (all caps after separator line)
if (trimmedLine.startsWith("————————")) {
if (i + 1 < lines.size()) {
QString nextLine = lines[i + 1].trimmed();
if (!nextLine.isEmpty() && nextLine.length() > 2 && nextLine.toUpper() == nextLine && nextLine != "WIFI") {
break;
}
}
continue; // Skip separator lines
}
if (trimmedLine.startsWith("Interface Name")) {
QStringList parts = trimmedLine.split(":");
if (parts.size() >= 2) {
interfaceName = parts[1].trimmed();
}
} else if (trimmedLine.startsWith("SSID")) {
QStringList parts = trimmedLine.split(":");
if (parts.size() >= 2) {
ssid = parts[1].trimmed();
}
} else if (trimmedLine.startsWith("Security")) {
QStringList parts = trimmedLine.split(":");
if (parts.size() >= 2) {
security = parts[1].trimmed();
}
}
}
} }
if (![interface powerOn]) { if (!ssid.isEmpty() && !interfaceName.isEmpty()) {
logger.debug() << "The interface is off"; logger.debug() << "Found active WiFi connection on" << interfaceName
return; << "SSID:" << ssid << "Security:" << security;
} else {
logger.debug() << "No active WiFi connection found";
} }
NSString* ssidNS = [interface ssid];
if (!ssidNS) {
logger.debug() << "WiFi is not in used";
return;
}
QString ssid = QString::fromNSString(ssidNS);
if (ssid.isEmpty()) {
logger.debug() << "WiFi doesn't have a valid SSID";
return;
}
CWSecurity security = [interface security];
if (security == kCWSecurityNone || security == kCWSecurityWEP) {
logger.debug() << "Unsecured network found!";
emit unsecuredNetwork(ssid, ssid);
return;
}
logger.debug() << "Secure WiFi interface";
} }
@@ -22,7 +22,6 @@
#include "logger.h" #include "logger.h"
#include "platforms/windows/daemon/windowsfirewall.h" #include "platforms/windows/daemon/windowsfirewall.h"
#include "platforms/windows/daemon/windowssplittunnel.h" #include "platforms/windows/daemon/windowssplittunnel.h"
#include "platforms/windows/windowscommons.h"
#include "windowsfirewall.h" #include "windowsfirewall.h"
#include "core/networkUtilities.h" #include "core/networkUtilities.h"
@@ -32,9 +32,28 @@ WindowsNetworkWatcher::~WindowsNetworkWatcher() {
} }
} }
LRESULT WindowsNetworkWatcher::PowerWndProcCallback(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
auto obj = reinterpret_cast<WindowsNetworkWatcher*>(GetWindowLongPtr(hwnd, GWLP_USERDATA));
if (!obj){
logger.debug() << "obj not casted";
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
switch (uMsg) {
case WM_POWERBROADCAST:
if (wParam == PBT_APMRESUMESUSPEND) {
emit obj->sleepMode();
}
break;
default:
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
return 0;
}
void WindowsNetworkWatcher::initialize() { void WindowsNetworkWatcher::initialize() {
logger.debug() << "initialize"; logger.debug() << "initialize";
DWORD negotiatedVersion; DWORD negotiatedVersion;
if (WlanOpenHandle(2, nullptr, &negotiatedVersion, &m_wlanHandle) != if (WlanOpenHandle(2, nullptr, &negotiatedVersion, &m_wlanHandle) !=
ERROR_SUCCESS) { ERROR_SUCCESS) {
@@ -51,6 +70,25 @@ void WindowsNetworkWatcher::initialize() {
return; return;
} }
const wchar_t* className = L"PowerMonitorClass";
WNDCLASS wc = { 0 };
wc.lpfnWndProc = &WindowsNetworkWatcher::PowerWndProcCallback;
wc.hInstance = GetModuleHandle(NULL);
wc.lpszClassName = className;
wc.cbWndExtra = sizeof(WindowsNetworkWatcher*);
if (!RegisterClass(&wc)) {
logger.debug() << "Failed to register window class in createPowerMonitorWindow.";
return;
}
HWND hwnd = CreateWindowEx(0, className, L"Power Monitor", 0, 0, 0, 0, 0, NULL, NULL, GetModuleHandle(NULL), static_cast<LPVOID>(this));
if (!hwnd) {
logger.debug() << "Failed to create window in createPowerMonitorWindow.";
return;
}
SetWindowLongPtr(hwnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(this));
logger.debug() << "callback registered"; logger.debug() << "callback registered";
} }
@@ -137,4 +175,4 @@ void WindowsNetworkWatcher::processWlan(PWLAN_NOTIFICATION_DATA data) {
logger.debug() << "Unsecure network:" << logger.sensitive(ssid) logger.debug() << "Unsecure network:" << logger.sensitive(ssid)
<< "id:" << logger.sensitive(bssid); << "id:" << logger.sensitive(bssid);
emit unsecuredNetwork(ssid, bssid); emit unsecuredNetwork(ssid, bssid);
} }
@@ -19,6 +19,7 @@ class WindowsNetworkWatcher final : public NetworkWatcherImpl {
private: private:
static void wlanCallback(PWLAN_NOTIFICATION_DATA data, PVOID context); static void wlanCallback(PWLAN_NOTIFICATION_DATA data, PVOID context);
static LRESULT PowerWndProcCallback(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
void processWlan(PWLAN_NOTIFICATION_DATA data); void processWlan(PWLAN_NOTIFICATION_DATA data);
@@ -179,6 +179,7 @@ void WindowsPingSender::pingEventReady() {
return; return;
} }
QString errmsg = WindowsUtils::getErrorMessage(); QString errmsg = WindowsUtils::getErrorMessage();
emit criticalPingError();
logger.error() << "No ping reply. Code: " << error logger.error() << "No ping reply. Code: " << error
<< " Message: " << errmsg; << " Message: " << errmsg;
return; return;
+5
View File
@@ -103,6 +103,11 @@ QString VpnProtocol::vpnGateway() const
return m_vpnGateway; return m_vpnGateway;
} }
QString VpnProtocol::vpnLocalAddress() const
{
return m_vpnLocalAddress;
}
VpnProtocol *VpnProtocol::factory(DockerContainer container, const QJsonObject &configuration) VpnProtocol *VpnProtocol::factory(DockerContainer container, const QJsonObject &configuration)
{ {
switch (container) { switch (container) {
+1
View File
@@ -63,6 +63,7 @@ public:
QString routeGateway() const; QString routeGateway() const;
QString vpnGateway() const; QString vpnGateway() const;
QString vpnLocalAddress() const;
static VpnProtocol* factory(amnezia::DockerContainer container, const QJsonObject &configuration); static VpnProtocol* factory(amnezia::DockerContainer container, const QJsonObject &configuration);
+7
View File
@@ -17,6 +17,13 @@ WireguardProtocol::WireguardProtocol(const QJsonObject &configuration, QObject *
[this](const QString &pubkey, const QDateTime &connectionTimestamp) { [this](const QString &pubkey, const QDateTime &connectionTimestamp) {
emit connectionStateChanged(Vpn::ConnectionState::Connected); emit connectionStateChanged(Vpn::ConnectionState::Connected);
}); });
connect(m_impl.get(), &ControllerImpl::statusUpdated, this,
[this](const QString& serverIpv4Gateway,
const QString& deviceIpv4Address, uint64_t txBytes,
uint64_t rxBytes) {
m_vpnLocalAddress = deviceIpv4Address;
});
connect(m_impl.get(), &ControllerImpl::disconnected, this, connect(m_impl.get(), &ControllerImpl::disconnected, this,
[this]() { emit connectionStateChanged(Vpn::ConnectionState::Disconnected); }); [this]() { emit connectionStateChanged(Vpn::ConnectionState::Disconnected); });
m_impl->initialize(nullptr, nullptr); m_impl->initialize(nullptr, nullptr);
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+72 -72
View File
@@ -94,12 +94,12 @@
<translation>%1 успешно установлен.</translation> <translation>%1 успешно установлен.</translation>
</message> </message>
<message> <message>
<location filename="../ui/controllers/api/apiConfigsController.cpp" line="472"/> <location filename="../ui/controllers/api/apiConfigsController.cpp" line="473"/>
<source>API config reloaded</source> <source>API config reloaded</source>
<translation>Конфигурация API перезагружена</translation> <translation>Конфигурация API перезагружена</translation>
</message> </message>
<message> <message>
<location filename="../ui/controllers/api/apiConfigsController.cpp" line="476"/> <location filename="../ui/controllers/api/apiConfigsController.cpp" line="477"/>
<source>Successfully changed the country of connection to %1</source> <source>Successfully changed the country of connection to %1</source>
<translation>Страна подключения изменена на %1</translation> <translation>Страна подключения изменена на %1</translation>
</message> </message>
@@ -2116,12 +2116,12 @@ subscription key</source>
<translation>Показать ключ</translation> <translation>Показать ключ</translation>
</message> </message>
<message> <message>
<location filename="../ui/qml/Pages2/PageSettingsApiSubscriptionKey.qml" line="147"/> <location filename="../ui/qml/Pages2/PageSettingsApiSubscriptionKey.qml" line="151"/>
<source>To read the QR code in the Amnezia app, tap + in the main menu &apos;QR code&apos;</source> <source>To read the QR code in the Amnezia app, tap + in the main menu &apos;QR code&apos;</source>
<translation>Для считывания QR-кода в приложении Amnezia выберите + в главном меню &apos;QR-код&apos;</translation> <translation>Для считывания QR-кода в приложении Amnezia выберите + в главном меню &apos;QR-код&apos;</translation>
</message> </message>
<message> <message>
<location filename="../ui/qml/Pages2/PageSettingsApiSubscriptionKey.qml" line="176"/> <location filename="../ui/qml/Pages2/PageSettingsApiSubscriptionKey.qml" line="180"/>
<source>Amnezia Premium Subscription key</source> <source>Amnezia Premium Subscription key</source>
<translation>Ключ подключения Amnezia Premium</translation> <translation>Ключ подключения Amnezia Premium</translation>
</message> </message>
@@ -3394,38 +3394,38 @@ subscription key</source>
<context> <context>
<name>PageSetupWizardInstalling</name> <name>PageSetupWizardInstalling</name>
<message> <message>
<location filename="../ui/qml/Pages2/PageSetupWizardInstalling.qml" line="59"/> <location filename="../ui/qml/Pages2/PageSetupWizardInstalling.qml" line="63"/>
<source>The server has already been added to the application</source> <source>The server has already been added to the application</source>
<translation>Сервер уже был добавлен в приложение</translation> <translation>Сервер уже был добавлен в приложение</translation>
</message> </message>
<message> <message>
<location filename="../ui/qml/Pages2/PageSetupWizardInstalling.qml" line="65"/> <location filename="../ui/qml/Pages2/PageSetupWizardInstalling.qml" line="69"/>
<source>Amnezia has detected that your server is currently </source> <source>Amnezia has detected that your server is currently </source>
<translation>Amnezia обнаружила, что ваш сервер в настоящее время </translation> <translation>Amnezia обнаружила, что ваш сервер в настоящее время </translation>
</message> </message>
<message> <message>
<location filename="../ui/qml/Pages2/PageSetupWizardInstalling.qml" line="66"/> <location filename="../ui/qml/Pages2/PageSetupWizardInstalling.qml" line="70"/>
<source>busy installing other software. Amnezia installation </source> <source>busy installing other software. Amnezia installation </source>
<translation>занят установкой других протоколов или сервисов. Установка Amnezia </translation> <translation>занят установкой других протоколов или сервисов. Установка Amnezia </translation>
</message> </message>
<message> <message>
<location filename="../ui/qml/Pages2/PageSetupWizardInstalling.qml" line="67"/> <location filename="../ui/qml/Pages2/PageSetupWizardInstalling.qml" line="71"/>
<source>will pause until the server finishes installing other software</source> <source>will pause until the server finishes installing other software</source>
<translation>будет приостановлена до тех пор, пока сервер не завершит установку другого ПО</translation> <translation>будет приостановлена до тех пор, пока сервер не завершит установку другого ПО</translation>
</message> </message>
<message> <message>
<location filename="../ui/qml/Pages2/PageSetupWizardInstalling.qml" line="106"/> <location filename="../ui/qml/Pages2/PageSetupWizardInstalling.qml" line="110"/>
<source>Installing</source> <source>Installing</source>
<translation>Установка</translation> <translation>Установка</translation>
</message> </message>
<message> <message>
<location filename="../ui/qml/Pages2/PageSetupWizardInstalling.qml" line="151"/> <location filename="../ui/qml/Pages2/PageSetupWizardInstalling.qml" line="155"/>
<source>Cancel installation</source> <source>Cancel installation</source>
<translation>Отменить установку</translation> <translation>Отменить установку</translation>
</message> </message>
<message> <message>
<location filename="../ui/qml/Pages2/PageSetupWizardInstalling.qml" line="22"/> <location filename="../ui/qml/Pages2/PageSetupWizardInstalling.qml" line="22"/>
<location filename="../ui/qml/Pages2/PageSetupWizardInstalling.qml" line="71"/> <location filename="../ui/qml/Pages2/PageSetupWizardInstalling.qml" line="75"/>
<source>Usually it takes no more than 5 minutes</source> <source>Usually it takes no more than 5 minutes</source>
<translation>Обычно это занимает не более 5 минут</translation> <translation>Обычно это занимает не более 5 минут</translation>
</message> </message>
@@ -3561,217 +3561,217 @@ subscription key</source>
<context> <context>
<name>PageShare</name> <name>PageShare</name>
<message> <message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="130"/> <location filename="../ui/qml/Pages2/PageShare.qml" line="125"/>
<source>OpenVPN native format</source> <source>OpenVPN native format</source>
<translation>Оригинальный формат OpenVPN</translation> <translation>Оригинальный формат OpenVPN</translation>
</message> </message>
<message> <message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="135"/> <location filename="../ui/qml/Pages2/PageShare.qml" line="130"/>
<source>WireGuard native format</source> <source>WireGuard native format</source>
<translation>Оригинальный формат WireGuard</translation> <translation>Оригинальный формат WireGuard</translation>
</message> </message>
<message> <message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="260"/> <location filename="../ui/qml/Pages2/PageShare.qml" line="255"/>
<source>Connection</source> <source>Connection</source>
<translation>Соединение</translation> <translation>Соединение</translation>
</message> </message>
<message> <message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="328"/> <location filename="../ui/qml/Pages2/PageShare.qml" line="323"/>
<location filename="../ui/qml/Pages2/PageShare.qml" line="329"/> <location filename="../ui/qml/Pages2/PageShare.qml" line="324"/>
<source>Server</source> <source>Server</source>
<translation>Сервер</translation> <translation>Сервер</translation>
</message> </message>
<message> <message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="39"/> <location filename="../ui/qml/Pages2/PageShare.qml" line="37"/>
<source>Config revoked</source> <source>Config revoked</source>
<translation>Конфигурация отозвана</translation> <translation>Конфигурация отозвана</translation>
</message> </message>
<message> <message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="55"/> <location filename="../ui/qml/Pages2/PageShare.qml" line="50"/>
<source>Save AmneziaVPN config</source> <source>Save AmneziaVPN config</source>
<translation>Сохранить конфигурацию AmneziaVPN</translation> <translation>Сохранить конфигурацию AmneziaVPN</translation>
</message> </message>
<message> <message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="62"/> <location filename="../ui/qml/Pages2/PageShare.qml" line="57"/>
<source>Save OpenVPN config</source> <source>Save OpenVPN config</source>
<translation>Сохранить конфигурацию OpenVPN</translation> <translation>Сохранить конфигурацию OpenVPN</translation>
</message> </message>
<message> <message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="69"/> <location filename="../ui/qml/Pages2/PageShare.qml" line="64"/>
<source>Save WireGuard config</source> <source>Save WireGuard config</source>
<translation>Сохранить конфигурацию WireGuard</translation> <translation>Сохранить конфигурацию WireGuard</translation>
</message> </message>
<message> <message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="76"/> <location filename="../ui/qml/Pages2/PageShare.qml" line="71"/>
<source>Save AmneziaWG config</source> <source>Save AmneziaWG config</source>
<translation>Сохранить конфигурацию AmneziaWG</translation> <translation>Сохранить конфигурацию AmneziaWG</translation>
</message> </message>
<message> <message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="83"/> <location filename="../ui/qml/Pages2/PageShare.qml" line="78"/>
<source>Save Shadowsocks config</source> <source>Save Shadowsocks config</source>
<translation>Сохранить конфигурацию Shadowsocks</translation> <translation>Сохранить конфигурацию Shadowsocks</translation>
</message> </message>
<message> <message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="90"/> <location filename="../ui/qml/Pages2/PageShare.qml" line="85"/>
<source>Save Cloak config</source> <source>Save Cloak config</source>
<translation>Сохранить конфигурацию Cloak</translation> <translation>Сохранить конфигурацию Cloak</translation>
</message> </message>
<message> <message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="97"/> <location filename="../ui/qml/Pages2/PageShare.qml" line="92"/>
<source>Save XRay config</source> <source>Save XRay config</source>
<translation>Сохранить конфигурацию XRay</translation> <translation>Сохранить конфигурацию XRay</translation>
</message> </message>
<message> <message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="106"/> <location filename="../ui/qml/Pages2/PageShare.qml" line="101"/>
<source>Connection to </source> <source>Connection to </source>
<translation>Подключение к </translation> <translation>Подключение к </translation>
</message> </message>
<message> <message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="107"/> <location filename="../ui/qml/Pages2/PageShare.qml" line="102"/>
<source>File with connection settings to </source> <source>File with connection settings to </source>
<translation>Файл с настройками подключения к </translation> <translation>Файл с настройками подключения к </translation>
</message> </message>
<message> <message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="125"/> <location filename="../ui/qml/Pages2/PageShare.qml" line="120"/>
<source>For the AmneziaVPN app</source> <source>For the AmneziaVPN app</source>
<translation>Для приложения AmneziaVPN</translation> <translation>Для приложения AmneziaVPN</translation>
</message> </message>
<message> <message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="140"/> <location filename="../ui/qml/Pages2/PageShare.qml" line="135"/>
<source>AmneziaWG native format</source> <source>AmneziaWG native format</source>
<translation>Оригинальный формат AmneziaWG</translation> <translation>Оригинальный формат AmneziaWG</translation>
</message> </message>
<message> <message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="145"/> <location filename="../ui/qml/Pages2/PageShare.qml" line="140"/>
<source>Shadowsocks native format</source> <source>Shadowsocks native format</source>
<translation>Оригинальный формат Shadowsocks</translation> <translation>Оригинальный формат Shadowsocks</translation>
</message> </message>
<message> <message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="150"/> <location filename="../ui/qml/Pages2/PageShare.qml" line="145"/>
<source>Cloak native format</source> <source>Cloak native format</source>
<translation>Оригинальный формат Cloak</translation> <translation>Оригинальный формат Cloak</translation>
</message> </message>
<message> <message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="155"/> <location filename="../ui/qml/Pages2/PageShare.qml" line="150"/>
<source>XRay native format</source> <source>XRay native format</source>
<translation>Оригинальный формат XRay</translation> <translation>Оригинальный формат XRay</translation>
</message> </message>
<message> <message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="183"/> <location filename="../ui/qml/Pages2/PageShare.qml" line="178"/>
<source>Share VPN Access</source> <source>Share VPN Access</source>
<translation>Поделиться VPN</translation> <translation>Поделиться VPN</translation>
</message> </message>
<message> <message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="217"/> <location filename="../ui/qml/Pages2/PageShare.qml" line="212"/>
<source>Share full access to the server and VPN</source> <source>Share full access to the server and VPN</source>
<translation>Поделиться полным доступом к серверу и VPN</translation> <translation>Поделиться полным доступом к серверу и VPN</translation>
</message> </message>
<message> <message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="218"/> <location filename="../ui/qml/Pages2/PageShare.qml" line="213"/>
<source>Use for your own devices, or share with those you trust to manage the server.</source> <source>Use for your own devices, or share with those you trust to manage the server.</source>
<translation>Используйте для собственных устройств или передайте управление сервером тем, кому вы доверяете.</translation> <translation>Используйте для собственных устройств или передайте управление сервером тем, кому вы доверяете.</translation>
</message> </message>
<message> <message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="275"/> <location filename="../ui/qml/Pages2/PageShare.qml" line="270"/>
<location filename="../ui/qml/Pages2/PageShare.qml" line="555"/> <location filename="../ui/qml/Pages2/PageShare.qml" line="550"/>
<source>Users</source> <source>Users</source>
<translation>Пользователи</translation> <translation>Пользователи</translation>
</message> </message>
<message> <message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="309"/> <location filename="../ui/qml/Pages2/PageShare.qml" line="304"/>
<source>User name</source> <source>User name</source>
<translation>Имя пользователя</translation> <translation>Имя пользователя</translation>
</message> </message>
<message> <message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="571"/> <location filename="../ui/qml/Pages2/PageShare.qml" line="566"/>
<source>Search</source> <source>Search</source>
<translation>Поиск</translation> <translation>Поиск</translation>
</message> </message>
<message> <message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="694"/> <location filename="../ui/qml/Pages2/PageShare.qml" line="689"/>
<source>Creation date: %1</source> <source>Creation date: %1</source>
<translation>Дата создания: %1</translation> <translation>Дата создания: %1</translation>
</message> </message>
<message> <message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="706"/> <location filename="../ui/qml/Pages2/PageShare.qml" line="701"/>
<source>Latest handshake: %1</source> <source>Latest handshake: %1</source>
<translation>Последнее рукопожатие: %1</translation> <translation>Последнее рукопожатие: %1</translation>
</message> </message>
<message> <message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="718"/> <location filename="../ui/qml/Pages2/PageShare.qml" line="713"/>
<source>Data received: %1</source> <source>Data received: %1</source>
<translation>Получено данных: %1</translation> <translation>Получено данных: %1</translation>
</message> </message>
<message> <message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="730"/> <location filename="../ui/qml/Pages2/PageShare.qml" line="725"/>
<source>Data sent: %1</source> <source>Data sent: %1</source>
<translation>Отправлено данных: %1</translation> <translation>Отправлено данных: %1</translation>
</message> </message>
<message> <message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="740"/> <location filename="../ui/qml/Pages2/PageShare.qml" line="735"/>
<source>Allowed IPs: %1</source> <source>Allowed IPs: %1</source>
<translation>Разрешенные подсети: %1</translation> <translation>Разрешенные подсети: %1</translation>
</message> </message>
<message> <message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="755"/> <location filename="../ui/qml/Pages2/PageShare.qml" line="750"/>
<source>Rename</source> <source>Rename</source>
<translation>Переименовать</translation> <translation>Переименовать</translation>
</message> </message>
<message> <message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="780"/> <location filename="../ui/qml/Pages2/PageShare.qml" line="775"/>
<source>Client name</source> <source>Client name</source>
<translation>Имя клиента</translation> <translation>Имя клиента</translation>
</message> </message>
<message> <message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="791"/> <location filename="../ui/qml/Pages2/PageShare.qml" line="786"/>
<source>Save</source> <source>Save</source>
<translation>Сохранить</translation> <translation>Сохранить</translation>
</message> </message>
<message> <message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="825"/> <location filename="../ui/qml/Pages2/PageShare.qml" line="820"/>
<source>Revoke</source> <source>Revoke</source>
<translation>Отозвать</translation> <translation>Отозвать</translation>
</message> </message>
<message> <message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="828"/> <location filename="../ui/qml/Pages2/PageShare.qml" line="823"/>
<source>Revoke the config for a user - %1?</source> <source>Revoke the config for a user - %1?</source>
<translation>Отозвать конфигурацию для пользователя - %1?</translation> <translation>Отозвать конфигурацию для пользователя - %1?</translation>
</message> </message>
<message> <message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="829"/> <location filename="../ui/qml/Pages2/PageShare.qml" line="824"/>
<source>The user will no longer be able to connect to your server.</source> <source>The user will no longer be able to connect to your server.</source>
<translation>Пользователь больше не сможет подключаться к вашему серверу.</translation> <translation>Пользователь больше не сможет подключаться к вашему серверу.</translation>
</message> </message>
<message> <message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="830"/> <location filename="../ui/qml/Pages2/PageShare.qml" line="825"/>
<source>Continue</source> <source>Continue</source>
<translation>Продолжить</translation> <translation>Продолжить</translation>
</message> </message>
<message> <message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="831"/> <location filename="../ui/qml/Pages2/PageShare.qml" line="826"/>
<source>Cancel</source> <source>Cancel</source>
<translation>Отменить</translation> <translation>Отменить</translation>
</message> </message>
<message> <message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="298"/> <location filename="../ui/qml/Pages2/PageShare.qml" line="293"/>
<source>Share VPN access without the ability to manage the server</source> <source>Share VPN access without the ability to manage the server</source>
<translation>Поделиться доступом к VPN без возможности управления сервером</translation> <translation>Поделиться доступом к VPN без возможности управления сервером</translation>
</message> </message>
<message> <message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="389"/> <location filename="../ui/qml/Pages2/PageShare.qml" line="384"/>
<location filename="../ui/qml/Pages2/PageShare.qml" line="390"/> <location filename="../ui/qml/Pages2/PageShare.qml" line="385"/>
<source>Protocol</source> <source>Protocol</source>
<translation>Протокол</translation> <translation>Протокол</translation>
</message> </message>
<message> <message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="496"/> <location filename="../ui/qml/Pages2/PageShare.qml" line="491"/>
<location filename="../ui/qml/Pages2/PageShare.qml" line="497"/> <location filename="../ui/qml/Pages2/PageShare.qml" line="492"/>
<source>Connection format</source> <source>Connection format</source>
<translation>Формат подключения</translation> <translation>Формат подключения</translation>
</message> </message>
<message> <message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="225"/> <location filename="../ui/qml/Pages2/PageShare.qml" line="220"/>
<location filename="../ui/qml/Pages2/PageShare.qml" line="537"/> <location filename="../ui/qml/Pages2/PageShare.qml" line="532"/>
<source>Share</source> <source>Share</source>
<translation>Поделиться</translation> <translation>Поделиться</translation>
</message> </message>
@@ -3810,7 +3810,7 @@ subscription key</source>
<translation>Скопировано</translation> <translation>Скопировано</translation>
</message> </message>
<message> <message>
<location filename="../ui/qml/Pages2/PageShareConnection.qml" line="319"/> <location filename="../ui/qml/Pages2/PageShareConnection.qml" line="323"/>
<source>To read the QR code in the Amnezia app, select &quot;Add server&quot; &quot;I have data to connect&quot; &quot;QR code, key or settings file&quot;</source> <source>To read the QR code in the Amnezia app, select &quot;Add server&quot; &quot;I have data to connect&quot; &quot;QR code, key or settings file&quot;</source>
<translation>Для считывания QR-кода в приложении Amnezia выберите &quot;Добавить сервер&quot; &quot;У меня есть данные для подключения&quot; &quot;Открыть файл конфигурации, ключ или QR-код&quot;</translation> <translation>Для считывания QR-кода в приложении Amnezia выберите &quot;Добавить сервер&quot; &quot;У меня есть данные для подключения&quot; &quot;Открыть файл конфигурации, ключ или QR-код&quot;</translation>
</message> </message>
@@ -3841,22 +3841,22 @@ subscription key</source>
<translation>Сервер</translation> <translation>Сервер</translation>
</message> </message>
<message> <message>
<location filename="../ui/qml/Pages2/PageShareFullAccess.qml" line="114"/> <location filename="../ui/qml/Pages2/PageShareFullAccess.qml" line="115"/>
<source>Accessing </source> <source>Accessing </source>
<translation>Доступ </translation> <translation>Доступ </translation>
</message> </message>
<message> <message>
<location filename="../ui/qml/Pages2/PageShareFullAccess.qml" line="115"/> <location filename="../ui/qml/Pages2/PageShareFullAccess.qml" line="116"/>
<source>File with accessing settings to </source> <source>File with accessing settings to </source>
<translation>Файл с настройками доступа к </translation> <translation>Файл с настройками доступа к </translation>
</message> </message>
<message> <message>
<location filename="../ui/qml/Pages2/PageShareFullAccess.qml" line="146"/> <location filename="../ui/qml/Pages2/PageShareFullAccess.qml" line="147"/>
<source>Share</source> <source>Share</source>
<translation>Поделиться</translation> <translation>Поделиться</translation>
</message> </message>
<message> <message>
<location filename="../ui/qml/Pages2/PageShareFullAccess.qml" line="154"/> <location filename="../ui/qml/Pages2/PageShareFullAccess.qml" line="155"/>
<source>Access error!</source> <source>Access error!</source>
<translation>Ошибка доступа!</translation> <translation>Ошибка доступа!</translation>
</message> </message>
@@ -5059,7 +5059,7 @@ FileZilla или другие SFTP-клиенты, а также смонтир
<context> <context>
<name>VpnConnection</name> <name>VpnConnection</name>
<message> <message>
<location filename="../vpnconnection.cpp" line="437"/> <location filename="../vpnconnection.cpp" line="492"/>
<source>Mbps</source> <source>Mbps</source>
<translation>Мбит/с</translation> <translation>Мбит/с</translation>
</message> </message>
@@ -5067,42 +5067,42 @@ FileZilla или другие SFTP-клиенты, а также смонтир
<context> <context>
<name>VpnProtocol</name> <name>VpnProtocol</name>
<message> <message>
<location filename="../protocols/vpnprotocol.cpp" line="133"/> <location filename="../protocols/vpnprotocol.cpp" line="138"/>
<source>Unknown</source> <source>Unknown</source>
<translation>Неизвестный</translation> <translation>Неизвестный</translation>
</message> </message>
<message> <message>
<location filename="../protocols/vpnprotocol.cpp" line="134"/> <location filename="../protocols/vpnprotocol.cpp" line="139"/>
<source>Disconnected</source> <source>Disconnected</source>
<translation>Отключено</translation> <translation>Отключено</translation>
</message> </message>
<message> <message>
<location filename="../protocols/vpnprotocol.cpp" line="135"/> <location filename="../protocols/vpnprotocol.cpp" line="140"/>
<source>Preparing</source> <source>Preparing</source>
<translation>Подготовка</translation> <translation>Подготовка</translation>
</message> </message>
<message> <message>
<location filename="../protocols/vpnprotocol.cpp" line="136"/> <location filename="../protocols/vpnprotocol.cpp" line="141"/>
<source>Connecting...</source> <source>Connecting...</source>
<translation>Подключение...</translation> <translation>Подключение...</translation>
</message> </message>
<message> <message>
<location filename="../protocols/vpnprotocol.cpp" line="137"/> <location filename="../protocols/vpnprotocol.cpp" line="142"/>
<source>Connected</source> <source>Connected</source>
<translation>Подключено</translation> <translation>Подключено</translation>
</message> </message>
<message> <message>
<location filename="../protocols/vpnprotocol.cpp" line="138"/> <location filename="../protocols/vpnprotocol.cpp" line="143"/>
<source>Disconnecting...</source> <source>Disconnecting...</source>
<translation>Отключение...</translation> <translation>Отключение...</translation>
</message> </message>
<message> <message>
<location filename="../protocols/vpnprotocol.cpp" line="139"/> <location filename="../protocols/vpnprotocol.cpp" line="144"/>
<source>Reconnecting...</source> <source>Reconnecting...</source>
<translation>Переподключение...</translation> <translation>Переподключение...</translation>
</message> </message>
<message> <message>
<location filename="../protocols/vpnprotocol.cpp" line="140"/> <location filename="../protocols/vpnprotocol.cpp" line="145"/>
<source>Error</source> <source>Error</source>
<translation>Ошибка</translation> <translation>Ошибка</translation>
</message> </message>
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+59 -4
View File
@@ -1,12 +1,16 @@
#include "qtimer.h" #include "vpnconnection.h"
#include <QDebug> #include <QDebug>
#include <QEventLoop> #include <QEventLoop>
#include <QFile> #include <QFile>
#include <QHostInfo> #include <QHostInfo>
#include <QJsonObject> #include <QJsonObject>
#include <QObject>
#include <QSharedPointer>
#include <QString>
#include <QStringList>
#include <QTimer>
#include "core/controllers/serverController.h"
#include <configurators/cloak_configurator.h> #include <configurators/cloak_configurator.h>
#include <configurators/openvpn_configurator.h> #include <configurators/openvpn_configurator.h>
#include <configurators/shadowsocks_configurator.h> #include <configurators/shadowsocks_configurator.h>
@@ -14,7 +18,6 @@
#ifdef AMNEZIA_DESKTOP #ifdef AMNEZIA_DESKTOP
#include "core/ipcclient.h" #include "core/ipcclient.h"
#include "ipc.h"
#include <protocols/wireguardprotocol.h> #include <protocols/wireguardprotocol.h>
#endif #endif
@@ -76,7 +79,6 @@ void VpnConnection::onKillSwitchModeChanged(bool enabled)
void VpnConnection::onConnectionStateChanged(Vpn::ConnectionState state) void VpnConnection::onConnectionStateChanged(Vpn::ConnectionState state)
{ {
#ifdef AMNEZIA_DESKTOP #ifdef AMNEZIA_DESKTOP
auto container = m_settings->defaultContainer(m_settings->defaultServerIndex()); auto container = m_settings->defaultContainer(m_settings->defaultServerIndex());
@@ -107,6 +109,10 @@ void VpnConnection::onConnectionStateChanged(Vpn::ConnectionState state)
} }
} }
if (container != DockerContainer::Ipsec) {
IpcClient::Interface()->startNetworkCheck(m_vpnProtocol->vpnLocalAddress(), m_vpnProtocol->vpnLocalAddress());
}
} else if (state == Vpn::ConnectionState::Error) { } else if (state == Vpn::ConnectionState::Error) {
IpcClient::Interface()->flushDns(); IpcClient::Interface()->flushDns();
@@ -118,6 +124,8 @@ void VpnConnection::onConnectionStateChanged(Vpn::ConnectionState state)
} else if (state == Vpn::ConnectionState::Connecting) { } else if (state == Vpn::ConnectionState::Connecting) {
} else if (state == Vpn::ConnectionState::Disconnected) { } else if (state == Vpn::ConnectionState::Disconnected) {
auto result = IpcClient::Interface()->stopNetworkCheck();
result.waitForFinished(3000);
} }
} }
#endif #endif
@@ -241,6 +249,10 @@ void VpnConnection::connectToVpn(int serverIndex, const ServerCredentials &crede
.arg(ContainerProps::containerToString(container)) .arg(ContainerProps::containerToString(container))
<< m_settings->routeMode(); << m_settings->routeMode();
#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS) && !defined(MACOS_NE) #if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS) && !defined(MACOS_NE)
if (m_IpcClient) {
m_IpcClient->close();
m_IpcClient = nullptr;
}
if (!m_IpcClient) { if (!m_IpcClient) {
m_IpcClient = new IpcClient(this); m_IpcClient = new IpcClient(this);
} }
@@ -259,6 +271,9 @@ void VpnConnection::connectToVpn(int serverIndex, const ServerCredentials &crede
emit connectionStateChanged(Vpn::ConnectionState::Connecting); emit connectionStateChanged(Vpn::ConnectionState::Connecting);
m_vpnConfiguration = vpnConfiguration; m_vpnConfiguration = vpnConfiguration;
m_serverIndex = serverIndex;
m_serverCredentials = credentials;
m_dockerContainer = container;
#ifdef AMNEZIA_DESKTOP #ifdef AMNEZIA_DESKTOP
if (m_vpnProtocol) { if (m_vpnProtocol) {
@@ -297,12 +312,52 @@ void VpnConnection::connectToVpn(int serverIndex, const ServerCredentials &crede
emit connectionStateChanged(Vpn::ConnectionState::Error); emit connectionStateChanged(Vpn::ConnectionState::Error);
} }
void VpnConnection::restartConnection()
{
// Only reconnect if VPN was connected before sleep/network change
if (!m_wasConnectedBeforeSleep) {
qDebug() << "VPN was not connected before sleep/network change, skipping reconnection";
return;
}
qDebug() << "VPN was connected before sleep/network change, attempting reconnection";
this->disconnectFromVpn();
#ifdef Q_OS_LINUX
QThread::msleep(5000);
#endif
this->connectToVpn(m_serverIndex, m_serverCredentials, m_dockerContainer, m_vpnConfiguration);
// Reset the flag after reconnection attempt
m_wasConnectedBeforeSleep = false;
}
void VpnConnection::createProtocolConnections() void VpnConnection::createProtocolConnections()
{ {
connect(m_vpnProtocol.data(), &VpnProtocol::protocolError, this, &VpnConnection::vpnProtocolError); connect(m_vpnProtocol.data(), &VpnProtocol::protocolError, this, &VpnConnection::vpnProtocolError);
connect(m_vpnProtocol.data(), SIGNAL(connectionStateChanged(Vpn::ConnectionState)), this, connect(m_vpnProtocol.data(), SIGNAL(connectionStateChanged(Vpn::ConnectionState)), this,
SLOT(onConnectionStateChanged(Vpn::ConnectionState))); SLOT(onConnectionStateChanged(Vpn::ConnectionState)));
connect(m_vpnProtocol.data(), SIGNAL(bytesChanged(quint64, quint64)), this, SLOT(onBytesChanged(quint64, quint64))); connect(m_vpnProtocol.data(), SIGNAL(bytesChanged(quint64, quint64)), this, SLOT(onBytesChanged(quint64, quint64)));
#ifdef AMNEZIA_DESKTOP
connect(IpcClient::Interface().data(), &IpcInterfaceReplica::connectionLose,
this, [this]() {
qDebug() << "Connection Lose";
auto result = IpcClient::Interface()->stopNetworkCheck();
result.waitForFinished(3000);
// Track VPN state before connection loss
m_wasConnectedBeforeSleep = isConnected();
qDebug() << "VPN was connected before connection loss:" << m_wasConnectedBeforeSleep;
this->restartConnection();
});
connect(IpcClient::Interface().data(), &IpcInterfaceReplica::networkChange,
this, [this]() {
qDebug() << "Network change";
// Track VPN state before network change (including sleep/wake)
m_wasConnectedBeforeSleep = isConnected();
qDebug() << "VPN was connected before network change:" << m_wasConnectedBeforeSleep;
this->restartConnection();
});
#endif
} }
void VpnConnection::appendKillSwitchConfig() void VpnConnection::appendKillSwitchConfig()
+8
View File
@@ -51,6 +51,7 @@ public slots:
const ServerCredentials &credentials, DockerContainer container, const QJsonObject &vpnConfiguration); const ServerCredentials &credentials, DockerContainer container, const QJsonObject &vpnConfiguration);
void disconnectFromVpn(); void disconnectFromVpn();
void restartConnection();
void addRoutes(const QStringList &ips); void addRoutes(const QStringList &ips);
void deleteRoutes(const QStringList &ips); void deleteRoutes(const QStringList &ips);
@@ -77,6 +78,13 @@ private:
QJsonObject m_routeMode; QJsonObject m_routeMode;
QString m_remoteAddress; QString m_remoteAddress;
ServerCredentials m_serverCredentials;
int m_serverIndex;
DockerContainer m_dockerContainer;
// Track VPN state before sleep for smart reconnection
bool m_wasConnectedBeforeSleep = false;
// Only for iOS for now, check counters // Only for iOS for now, check counters
QTimer m_checkTimer; QTimer m_checkTimer;
+5
View File
@@ -36,5 +36,10 @@ 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 startNetworkCheck(const QString& serverIpv4Gateway, const QString& deviceIpv4Address) );
SLOT( bool stopNetworkCheck() );
SIGNAL( connectionLose() );
SIGNAL( networkChange() );
}; };
+23 -1
View File
@@ -1,9 +1,17 @@
#include "ipcserver.h" #include "ipcserver.h"
#include <QDateTime> #include <QDateTime>
#include <QDebug>
#include <QFileInfo> #include <QFileInfo>
#include <QHostAddress>
#include <QJsonObject>
#include <QLocalServer>
#include <QLocalSocket> #include <QLocalSocket>
#include <QObject> #include <QObject>
#include <QRemoteObjectHost>
#include <QRemoteObjectNode>
#include <QString>
#include <QStringList>
#include "logger.h" #include "logger.h"
#include "router.h" #include "router.h"
@@ -16,8 +24,8 @@
IpcServer::IpcServer(QObject *parent) : IpcInterfaceSource(parent) IpcServer::IpcServer(QObject *parent) : IpcInterfaceSource(parent)
{ {
connect(&m_pingHelper, &PingHelper::connectionLose, this, &IpcServer::connectionLose);
} }
int IpcServer::createPrivilegedProcess() int IpcServer::createPrivilegedProcess()
@@ -179,6 +187,20 @@ void IpcServer::setLogsEnabled(bool enabled)
} }
} }
bool IpcServer::startNetworkCheck(const QString& serverIpv4Gateway, const QString& deviceIpv4Address)
{
qDebug() << "startNetworkCheck";
m_pingHelper.start(serverIpv4Gateway, deviceIpv4Address);
return true;
}
bool IpcServer::stopNetworkCheck()
{
qDebug() << "stopNetworkCheck";
m_pingHelper.stop();
return true;
}
bool IpcServer::resetKillSwitchAllowedRange(QStringList ranges) bool IpcServer::resetKillSwitchAllowedRange(QStringList ranges)
{ {
return KillSwitch::instance()->resetAllowedRange(ranges); return KillSwitch::instance()->resetAllowedRange(ranges);
+5
View File
@@ -6,6 +6,7 @@
#include <QRemoteObjectNode> #include <QRemoteObjectNode>
#include <QJsonObject> #include <QJsonObject>
#include "../client/daemon/interfaceconfig.h" #include "../client/daemon/interfaceconfig.h"
#include "../client/mozilla/pinghelper.h"
#include "ipc.h" #include "ipc.h"
#include "ipcserverprocess.h" #include "ipcserverprocess.h"
@@ -42,6 +43,8 @@ public:
virtual bool disableKillSwitch() override; virtual bool disableKillSwitch() override;
virtual bool refreshKillSwitch( bool enabled ) override; virtual bool refreshKillSwitch( bool enabled ) 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 startNetworkCheck(const QString& serverIpv4Gateway, const QString& deviceIpv4Address) override;
virtual bool stopNetworkCheck() override;
private: private:
int m_localpid = 0; int m_localpid = 0;
@@ -61,6 +64,8 @@ private:
}; };
QMap<int, ProcessDescriptor> m_processes; QMap<int, ProcessDescriptor> m_processes;
PingHelper m_pingHelper;
}; };
#endif // IPCSERVER_H #endif // IPCSERVER_H
+2 -2
View File
@@ -109,7 +109,6 @@ set(HEADERS ${HEADERS}
${CMAKE_CURRENT_LIST_DIR}/../../client/mozilla/controllerimpl.h ${CMAKE_CURRENT_LIST_DIR}/../../client/mozilla/controllerimpl.h
${CMAKE_CURRENT_LIST_DIR}/../../client/mozilla/dnspingsender.h ${CMAKE_CURRENT_LIST_DIR}/../../client/mozilla/dnspingsender.h
${CMAKE_CURRENT_LIST_DIR}/../../client/mozilla/localsocketcontroller.h
${CMAKE_CURRENT_LIST_DIR}/../../client/mozilla/networkwatcher.h ${CMAKE_CURRENT_LIST_DIR}/../../client/mozilla/networkwatcher.h
${CMAKE_CURRENT_LIST_DIR}/../../client/mozilla/networkwatcherimpl.h ${CMAKE_CURRENT_LIST_DIR}/../../client/mozilla/networkwatcherimpl.h
${CMAKE_CURRENT_LIST_DIR}/../../client/mozilla/pinghelper.h ${CMAKE_CURRENT_LIST_DIR}/../../client/mozilla/pinghelper.h
@@ -133,7 +132,6 @@ set(SOURCES ${SOURCES}
${CMAKE_CURRENT_LIST_DIR}/../../client/mozilla/shared/leakdetector.cpp ${CMAKE_CURRENT_LIST_DIR}/../../client/mozilla/shared/leakdetector.cpp
${CMAKE_CURRENT_LIST_DIR}/../../client/mozilla/dnspingsender.cpp ${CMAKE_CURRENT_LIST_DIR}/../../client/mozilla/dnspingsender.cpp
${CMAKE_CURRENT_LIST_DIR}/../../client/mozilla/localsocketcontroller.cpp
${CMAKE_CURRENT_LIST_DIR}/../../client/mozilla/networkwatcher.cpp ${CMAKE_CURRENT_LIST_DIR}/../../client/mozilla/networkwatcher.cpp
${CMAKE_CURRENT_LIST_DIR}/../../client/mozilla/pinghelper.cpp ${CMAKE_CURRENT_LIST_DIR}/../../client/mozilla/pinghelper.cpp
${CMAKE_CURRENT_LIST_DIR}/../../client/mozilla/pingsender.cpp ${CMAKE_CURRENT_LIST_DIR}/../../client/mozilla/pingsender.cpp
@@ -282,6 +280,7 @@ if(LINUX)
${CMAKE_CURRENT_SOURCE_DIR}/../../client/platforms/linux/linuxnetworkwatcher.h ${CMAKE_CURRENT_SOURCE_DIR}/../../client/platforms/linux/linuxnetworkwatcher.h
${CMAKE_CURRENT_SOURCE_DIR}/../../client/platforms/linux/linuxnetworkwatcherworker.h ${CMAKE_CURRENT_SOURCE_DIR}/../../client/platforms/linux/linuxnetworkwatcherworker.h
${CMAKE_CURRENT_SOURCE_DIR}/../../client/platforms/linux/linuxdependencies.h ${CMAKE_CURRENT_SOURCE_DIR}/../../client/platforms/linux/linuxdependencies.h
${CMAKE_CURRENT_SOURCE_DIR}/../../client/platforms/linux/linuxpingsender.h
${CMAKE_CURRENT_SOURCE_DIR}/../../client/platforms/linux/daemon/iputilslinux.h ${CMAKE_CURRENT_SOURCE_DIR}/../../client/platforms/linux/daemon/iputilslinux.h
${CMAKE_CURRENT_SOURCE_DIR}/../../client/platforms/linux/daemon/dbustypeslinux.h ${CMAKE_CURRENT_SOURCE_DIR}/../../client/platforms/linux/daemon/dbustypeslinux.h
${CMAKE_CURRENT_SOURCE_DIR}/../../client/platforms/linux/daemon/linuxdaemon.h ${CMAKE_CURRENT_SOURCE_DIR}/../../client/platforms/linux/daemon/linuxdaemon.h
@@ -296,6 +295,7 @@ if(LINUX)
${CMAKE_CURRENT_SOURCE_DIR}/../../client/platforms/linux/linuxnetworkwatcher.cpp ${CMAKE_CURRENT_SOURCE_DIR}/../../client/platforms/linux/linuxnetworkwatcher.cpp
${CMAKE_CURRENT_SOURCE_DIR}/../../client/platforms/linux/linuxnetworkwatcherworker.cpp ${CMAKE_CURRENT_SOURCE_DIR}/../../client/platforms/linux/linuxnetworkwatcherworker.cpp
${CMAKE_CURRENT_SOURCE_DIR}/../../client/platforms/linux/linuxdependencies.cpp ${CMAKE_CURRENT_SOURCE_DIR}/../../client/platforms/linux/linuxdependencies.cpp
${CMAKE_CURRENT_SOURCE_DIR}/../../client/platforms/linux/linuxpingsender.cpp
${CMAKE_CURRENT_SOURCE_DIR}/../../client/platforms/linux/daemon/dnsutilslinux.cpp ${CMAKE_CURRENT_SOURCE_DIR}/../../client/platforms/linux/daemon/dnsutilslinux.cpp
${CMAKE_CURRENT_SOURCE_DIR}/../../client/platforms/linux/daemon/iputilslinux.cpp ${CMAKE_CURRENT_SOURCE_DIR}/../../client/platforms/linux/daemon/iputilslinux.cpp
${CMAKE_CURRENT_SOURCE_DIR}/../../client/platforms/linux/daemon/linuxdaemon.cpp ${CMAKE_CURRENT_SOURCE_DIR}/../../client/platforms/linux/daemon/linuxdaemon.cpp
+8 -2
View File
@@ -1,11 +1,15 @@
#include "localserver.h"
#include <QCoreApplication> #include <QCoreApplication>
#include <QDebug>
#include <QFileInfo> #include <QFileInfo>
#include <QLocalServer> #include <QLocalServer>
#include <QLocalSocket> #include <QLocalSocket>
#include <QObject>
#include <QSharedPointer>
#include <QString>
#include "ipc.h" #include "ipc.h"
#include "localserver.h"
#include "killswitch.h" #include "killswitch.h"
#include "logger.h" #include "logger.h"
@@ -46,6 +50,8 @@ LocalServer::LocalServer(QObject *parent) : QObject(parent),
return; return;
} }
m_networkWatcher.initialize();
connect(&m_networkWatcher, &NetworkWatcher::sleepMode, &m_ipcServer, &IpcServer::networkChange);
KillSwitch::instance()->init(); KillSwitch::instance()->init();
#ifdef Q_OS_LINUX #ifdef Q_OS_LINUX
+3 -1
View File
@@ -11,7 +11,7 @@
#include "ipcserver.h" #include "ipcserver.h"
#include "../../client/daemon/daemonlocalserver.h" #include "../../client/daemon/daemonlocalserver.h"
#include "../../client/mozilla/networkwatcher.h"
#ifdef Q_OS_WIN #ifdef Q_OS_WIN
#include "windows/daemon/windowsdaemon.h" #include "windows/daemon/windowsdaemon.h"
@@ -41,6 +41,8 @@ public:
IpcProcessTun2Socks m_tun2socks; IpcProcessTun2Socks m_tun2socks;
QRemoteObjectHost m_serverNode; QRemoteObjectHost m_serverNode;
bool m_isRemotingEnabled = false; bool m_isRemotingEnabled = false;
NetworkWatcher m_networkWatcher;
#ifdef Q_OS_LINUX #ifdef Q_OS_LINUX
DaemonLocalServer server{qApp}; DaemonLocalServer server{qApp};
LinuxDaemon daemon; LinuxDaemon daemon;