mirror of
https://github.com/amnezia-vpn/amnezia-client.git
synced 2026-06-22 02:01:08 +07:00
Compare commits
19 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ff589f47c2 | |||
| f0ca9772d3 | |||
| 23b530a0f8 | |||
| 511b8fa6cc | |||
| 38082f9940 | |||
| 71691fa01e | |||
| 62d9bcaf7f | |||
| 5ef8254cba | |||
| f767171c06 | |||
| eff460b227 | |||
| 319043818a | |||
| e730521576 | |||
| 517930dd22 | |||
| 26994c21b1 | |||
| 681eb5aa86 | |||
| 4b86425992 | |||
| 9b41ed66bb | |||
| 8bb4fa3f35 | |||
| e792117be1 |
+1
-1
Submodule client/3rd-prebuilt updated: 02a00ee00d...efad1a5b5c
Vendored
+1
-1
Submodule client/3rd/amneziawg-apple updated: 811af0a83b...76e7db556a
@@ -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
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ public:
|
|||||||
static QSharedPointer<PrivilegedProcess> CreatePrivilegedProcess();
|
static QSharedPointer<PrivilegedProcess> CreatePrivilegedProcess();
|
||||||
|
|
||||||
bool isSocketConnected() const;
|
bool isSocketConnected() const;
|
||||||
|
void close();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
|
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
@@ -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();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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";
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
|||||||
@@ -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, ¬ifyPortRef, sleepWakeupCallBack, ¬ifierObj);
|
||||||
|
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(¬ifierObj);
|
||||||
|
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 don’t 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;
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
+1413
-802
File diff suppressed because it is too large
Load Diff
+1413
-810
File diff suppressed because it is too large
Load Diff
+1413
-802
File diff suppressed because it is too large
Load Diff
+1416
-801
File diff suppressed because it is too large
Load Diff
@@ -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 → 'QR code'</source>
|
<source>To read the QR code in the Amnezia app, tap + in the main menu → 'QR code'</source>
|
||||||
<translation>Для считывания QR-кода в приложении Amnezia выберите + в главном меню → 'QR-код'</translation>
|
<translation>Для считывания QR-кода в приложении Amnezia выберите + в главном меню → 'QR-код'</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 "Add server" → "I have data to connect" → "QR code, key or settings file"</source>
|
<source>To read the QR code in the Amnezia app, select "Add server" → "I have data to connect" → "QR code, key or settings file"</source>
|
||||||
<translation>Для считывания QR-кода в приложении Amnezia выберите "Добавить сервер" → "У меня есть данные для подключения" → "Открыть файл конфигурации, ключ или QR-код"</translation>
|
<translation>Для считывания QR-кода в приложении Amnezia выберите "Добавить сервер" → "У меня есть данные для подключения" → "Открыть файл конфигурации, ключ или QR-код"</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>
|
||||||
|
|||||||
+1430
-823
File diff suppressed because it is too large
Load Diff
+1410
-803
File diff suppressed because it is too large
Load Diff
+1425
-830
File diff suppressed because it is too large
Load Diff
@@ -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()
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|
||||||
|
|||||||
@@ -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
@@ -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);
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
Reference in New Issue
Block a user