Add network status check for AWG/WG protocol
This commit is contained in:
parent
9dea98f020
commit
e792117be1
11 changed files with 304 additions and 16 deletions
|
@ -33,6 +33,10 @@ set(HEADERS ${HEADERS}
|
||||||
# Mozilla headres
|
# Mozilla headres
|
||||||
set(HEADERS ${HEADERS}
|
set(HEADERS ${HEADERS}
|
||||||
${CLIENT_ROOT_DIR}/mozilla/models/server.h
|
${CLIENT_ROOT_DIR}/mozilla/models/server.h
|
||||||
|
${CLIENT_ROOT_DIR}/mozilla/dnspingsender.h
|
||||||
|
${CLIENT_ROOT_DIR}/mozilla/pinghelper.h
|
||||||
|
${CLIENT_ROOT_DIR}/mozilla/pingsender.h
|
||||||
|
${CLIENT_ROOT_DIR}/mozilla/pingsenderfactory.h
|
||||||
${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
|
||||||
|
@ -84,6 +88,10 @@ set(SOURCES ${SOURCES}
|
||||||
# Mozilla sources
|
# Mozilla sources
|
||||||
set(SOURCES ${SOURCES}
|
set(SOURCES ${SOURCES}
|
||||||
${CLIENT_ROOT_DIR}/mozilla/models/server.cpp
|
${CLIENT_ROOT_DIR}/mozilla/models/server.cpp
|
||||||
|
${CLIENT_ROOT_DIR}/mozilla/dnspingsender.cpp
|
||||||
|
${CLIENT_ROOT_DIR}/mozilla/pinghelper.cpp
|
||||||
|
${CLIENT_ROOT_DIR}/mozilla/pingsender.cpp
|
||||||
|
${CLIENT_ROOT_DIR}/mozilla/pingsenderfactory.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
|
${CLIENT_ROOT_DIR}/mozilla/localsocketcontroller.cpp
|
||||||
|
@ -147,13 +155,25 @@ set(SOURCES ${SOURCES}
|
||||||
${UI_CONTROLLERS_CPP}
|
${UI_CONTROLLERS_CPP}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if (LINUX)
|
||||||
|
set(HEADERS ${HEADERS}
|
||||||
|
${CLIENT_ROOT_DIR}/platforms/linux/linuxpingsender.h
|
||||||
|
)
|
||||||
|
|
||||||
|
set(SOURCES ${SOURCES}
|
||||||
|
${CLIENT_ROOT_DIR}/platforms/linux/linuxpingsender.cpp
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
if(WIN32)
|
if(WIN32)
|
||||||
set(HEADERS ${HEADERS}
|
set(HEADERS ${HEADERS}
|
||||||
${CLIENT_ROOT_DIR}/protocols/ikev2_vpn_protocol_windows.h
|
${CLIENT_ROOT_DIR}/protocols/ikev2_vpn_protocol_windows.h
|
||||||
|
${CLIENT_ROOT_DIR}/platforms/windows/windowspingsender.h
|
||||||
)
|
)
|
||||||
|
|
||||||
set(SOURCES ${SOURCES}
|
set(SOURCES ${SOURCES}
|
||||||
${CLIENT_ROOT_DIR}/protocols/ikev2_vpn_protocol_windows.cpp
|
${CLIENT_ROOT_DIR}/protocols/ikev2_vpn_protocol_windows.cpp
|
||||||
|
${CLIENT_ROOT_DIR}/platforms/windows/windowspingsender.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
set(RESOURCES ${RESOURCES}
|
set(RESOURCES ${RESOURCES}
|
||||||
|
@ -161,6 +181,16 @@ if(WIN32)
|
||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if (APPLE AND NOT IOS AND NOT MACOS_NE)
|
||||||
|
set(HEADERS ${HEADERS}
|
||||||
|
${CLIENT_ROOT_DIR}/platforms/macos/macospingsender.h
|
||||||
|
)
|
||||||
|
|
||||||
|
set(SOURCES ${SOURCES}
|
||||||
|
${CLIENT_ROOT_DIR}/platforms/macos/macosspingsender.cpp
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
if(WIN32 OR (APPLE AND NOT IOS) OR (LINUX AND NOT ANDROID))
|
if(WIN32 OR (APPLE AND NOT IOS) OR (LINUX AND NOT ANDROID))
|
||||||
message("Client desktop build")
|
message("Client desktop build")
|
||||||
add_compile_definitions(AMNEZIA_DESKTOP)
|
add_compile_definitions(AMNEZIA_DESKTOP)
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#include <QJsonObject>
|
#include <QJsonObject>
|
||||||
#include <QJsonValue>
|
#include <QJsonValue>
|
||||||
#include <QStandardPaths>
|
#include <QStandardPaths>
|
||||||
|
#include <QThread>
|
||||||
|
|
||||||
#include "ipaddress.h"
|
#include "ipaddress.h"
|
||||||
#include "leakdetector.h"
|
#include "leakdetector.h"
|
||||||
|
@ -48,6 +49,15 @@ LocalSocketController::LocalSocketController() {
|
||||||
m_initializingTimer.setSingleShot(true);
|
m_initializingTimer.setSingleShot(true);
|
||||||
connect(&m_initializingTimer, &QTimer::timeout, this,
|
connect(&m_initializingTimer, &QTimer::timeout, this,
|
||||||
&LocalSocketController::initializeInternal);
|
&LocalSocketController::initializeInternal);
|
||||||
|
|
||||||
|
connect(&m_pingHelper, &PingHelper::connectionLose, this, [this]() {
|
||||||
|
logger.debug() << "Connection Lose";
|
||||||
|
m_pingHelper.stop();
|
||||||
|
this->deactivate();
|
||||||
|
QThread::msleep(3000);
|
||||||
|
this->activate(m_RawConfig);
|
||||||
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
LocalSocketController::~LocalSocketController() {
|
LocalSocketController::~LocalSocketController() {
|
||||||
|
@ -116,6 +126,8 @@ void LocalSocketController::daemonConnected() {
|
||||||
|
|
||||||
void LocalSocketController::activate(const QJsonObject &rawConfig) {
|
void LocalSocketController::activate(const QJsonObject &rawConfig) {
|
||||||
|
|
||||||
|
m_RawConfig = 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();
|
||||||
|
@ -258,6 +270,7 @@ void LocalSocketController::activate(const QJsonObject &rawConfig) {
|
||||||
json.insert(amnezia::config_key::transportPacketMagicHeader, wgConfig.value(amnezia::config_key::transportPacketMagicHeader));
|
json.insert(amnezia::config_key::transportPacketMagicHeader, wgConfig.value(amnezia::config_key::transportPacketMagicHeader));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
write(json);
|
write(json);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -362,6 +375,8 @@ void LocalSocketController::parseCommand(const QByteArray& command) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
qDebug() << command;
|
||||||
|
|
||||||
QJsonObject obj = json.object();
|
QJsonObject obj = json.object();
|
||||||
QJsonValue typeValue = obj.value("type");
|
QJsonValue typeValue = obj.value("type");
|
||||||
if (!typeValue.isString()) {
|
if (!typeValue.isString()) {
|
||||||
|
@ -406,6 +421,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";
|
||||||
|
@ -418,6 +434,8 @@ void LocalSocketController::parseCommand(const QByteArray& command) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_pingHelper.start(serverIpv4Gateway.toString(), deviceIpv4Address.toString());
|
||||||
|
|
||||||
QJsonValue txBytes = obj.value("txBytes");
|
QJsonValue txBytes = obj.value("txBytes");
|
||||||
if (!txBytes.isDouble()) {
|
if (!txBytes.isDouble()) {
|
||||||
logger.error() << "Unexpected txBytes value";
|
logger.error() << "Unexpected txBytes value";
|
||||||
|
@ -451,6 +469,7 @@ void LocalSocketController::parseCommand(const QByteArray& command) {
|
||||||
logger.debug() << "Handshake completed with:"
|
logger.debug() << "Handshake completed with:"
|
||||||
<< pubkey.toString();
|
<< pubkey.toString();
|
||||||
emit connected(pubkey.toString());
|
emit connected(pubkey.toString());
|
||||||
|
checkStatus();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,9 @@
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
|
||||||
#include "controllerimpl.h"
|
#include "controllerimpl.h"
|
||||||
|
#include "mozilla/pinghelper.h"
|
||||||
|
#include "qjsonobject.h"
|
||||||
|
|
||||||
|
|
||||||
class QJsonObject;
|
class QJsonObject;
|
||||||
|
|
||||||
|
@ -60,7 +63,11 @@ class LocalSocketController final : public ControllerImpl {
|
||||||
|
|
||||||
std::function<void(const QString&)> m_logCallback = nullptr;
|
std::function<void(const QString&)> m_logCallback = nullptr;
|
||||||
|
|
||||||
|
QJsonObject m_RawConfig;
|
||||||
|
PingHelper m_pingHelper;
|
||||||
|
|
||||||
QTimer m_initializingTimer;
|
QTimer m_initializingTimer;
|
||||||
|
QTimer m_statusTimer;
|
||||||
uint32_t m_initializingRetry = 0;
|
uint32_t m_initializingRetry = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
185
client/platforms/linux/linuxpingsender.cpp
Normal file
185
client/platforms/linux/linuxpingsender.cpp
Normal file
|
@ -0,0 +1,185 @@
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
#include "linuxpingsender.h"
|
||||||
|
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <linux/filter.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <netinet/ip.h>
|
||||||
|
#include <netinet/ip_icmp.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include <QSocketNotifier>
|
||||||
|
#include <QtEndian>
|
||||||
|
|
||||||
|
#include "leakdetector.h"
|
||||||
|
#include "logger.h"
|
||||||
|
#include "qhostaddress.h"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
Logger logger("LinuxPingSender");
|
||||||
|
}
|
||||||
|
|
||||||
|
int LinuxPingSender::createSocket() {
|
||||||
|
// Try creating an ICMP socket. This would be the ideal choice, but it can
|
||||||
|
// fail depending on the kernel config (see: sys.net.ipv4.ping_group_range)
|
||||||
|
m_socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_ICMP);
|
||||||
|
if (m_socket >= 0) {
|
||||||
|
m_ident = 0;
|
||||||
|
return m_socket;
|
||||||
|
}
|
||||||
|
if ((errno != EPERM) && (errno != EACCES)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// As a fallback, create a raw socket, which requires root permissions
|
||||||
|
// or CAP_NET_RAW to be granted to the VPN client.
|
||||||
|
m_socket = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
|
||||||
|
if (m_socket < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
m_ident = getpid() & 0xffff;
|
||||||
|
|
||||||
|
// Attach a BPF filter to discard everything but replies to our echo.
|
||||||
|
struct sock_filter bpf_prog[] = {
|
||||||
|
BPF_STMT(BPF_LDX | BPF_B | BPF_MSH, 0), /* Skip IP header. */
|
||||||
|
BPF_STMT(BPF_LD | BPF_H | BPF_IND, 4), /* Load icmp echo ident */
|
||||||
|
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, m_ident, 1, 0), /* Ours? */
|
||||||
|
BPF_STMT(BPF_RET | BPF_K, 0), /* Unexpected identifier. Reject. */
|
||||||
|
BPF_STMT(BPF_LD | BPF_B | BPF_IND, 0), /* Load icmp type */
|
||||||
|
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, ICMP_ECHOREPLY, 1, 0), /* Echo? */
|
||||||
|
BPF_STMT(BPF_RET | BPF_K, 0), /* Unexpected type. Reject. */
|
||||||
|
BPF_STMT(BPF_RET | BPF_K, ~0U), /* Packet passes the filter. */
|
||||||
|
};
|
||||||
|
struct sock_fprog filter = {
|
||||||
|
.len = sizeof(bpf_prog) / sizeof(struct sock_filter),
|
||||||
|
.filter = bpf_prog,
|
||||||
|
};
|
||||||
|
setsockopt(m_socket, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter));
|
||||||
|
|
||||||
|
return m_socket;
|
||||||
|
}
|
||||||
|
|
||||||
|
LinuxPingSender::LinuxPingSender(const QHostAddress& source, QObject* parent)
|
||||||
|
: PingSender(parent) {
|
||||||
|
MZ_COUNT_CTOR(LinuxPingSender);
|
||||||
|
|
||||||
|
logger.debug() << "LinuxPingSender(" + logger.sensitive(source.toString()) +
|
||||||
|
") created";
|
||||||
|
|
||||||
|
m_socket = createSocket();
|
||||||
|
if (m_socket < 0) {
|
||||||
|
logger.error() << "Socket creation error: " << strerror(errno);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
quint32 ipv4addr = INADDR_ANY;
|
||||||
|
if (!source.isNull()) {
|
||||||
|
ipv4addr = source.toIPv4Address();
|
||||||
|
}
|
||||||
|
struct sockaddr_in addr;
|
||||||
|
memset(&addr, 0, sizeof addr);
|
||||||
|
addr.sin_family = AF_INET;
|
||||||
|
addr.sin_addr.s_addr = qToBigEndian<quint32>(ipv4addr);
|
||||||
|
|
||||||
|
if (bind(m_socket, (struct sockaddr*)&addr, sizeof(addr)) != 0) {
|
||||||
|
close(m_socket);
|
||||||
|
m_socket = -1;
|
||||||
|
logger.error() << "bind error:" << strerror(errno);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_notifier = new QSocketNotifier(m_socket, QSocketNotifier::Read, this);
|
||||||
|
if (m_ident) {
|
||||||
|
connect(m_notifier, &QSocketNotifier::activated, this,
|
||||||
|
&LinuxPingSender::rawSocketReady);
|
||||||
|
} else {
|
||||||
|
connect(m_notifier, &QSocketNotifier::activated, this,
|
||||||
|
&LinuxPingSender::icmpSocketReady);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LinuxPingSender::~LinuxPingSender() {
|
||||||
|
MZ_COUNT_DTOR(LinuxPingSender);
|
||||||
|
if (m_socket >= 0) {
|
||||||
|
close(m_socket);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LinuxPingSender::sendPing(const QHostAddress& dest, quint16 sequence) {
|
||||||
|
quint32 ipv4dest = dest.toIPv4Address();
|
||||||
|
struct sockaddr_in addr;
|
||||||
|
memset(&addr, 0, sizeof(addr));
|
||||||
|
addr.sin_family = AF_INET;
|
||||||
|
addr.sin_addr.s_addr = qToBigEndian<quint32>(ipv4dest);
|
||||||
|
|
||||||
|
struct icmphdr packet;
|
||||||
|
memset(&packet, 0, sizeof(packet));
|
||||||
|
packet.type = ICMP_ECHO;
|
||||||
|
packet.un.echo.id = htons(m_ident);
|
||||||
|
packet.un.echo.sequence = htons(sequence);
|
||||||
|
packet.checksum = inetChecksum(&packet, sizeof(packet));
|
||||||
|
|
||||||
|
int rc = sendto(m_socket, &packet, sizeof(packet), 0, (struct sockaddr*)&addr,
|
||||||
|
sizeof(addr));
|
||||||
|
if (rc < 0) {
|
||||||
|
logger.error() << "failed to send:" << strerror(errno);
|
||||||
|
if (errno == ENETUNREACH) {
|
||||||
|
emit criticalPingError();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LinuxPingSender::icmpSocketReady() {
|
||||||
|
socklen_t slen = 0;
|
||||||
|
unsigned char data[2048];
|
||||||
|
int rc = recvfrom(m_socket, data, sizeof(data), MSG_DONTWAIT, NULL, &slen);
|
||||||
|
if (rc <= 0) {
|
||||||
|
logger.error() << "recvfrom failed:" << strerror(errno);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct icmphdr packet;
|
||||||
|
if (rc >= (int)sizeof(packet)) {
|
||||||
|
memcpy(&packet, data, sizeof(packet));
|
||||||
|
if (packet.type == ICMP_ECHOREPLY) {
|
||||||
|
emit recvPing(htons(packet.un.echo.sequence));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LinuxPingSender::rawSocketReady() {
|
||||||
|
socklen_t slen = 0;
|
||||||
|
unsigned char data[2048];
|
||||||
|
int rc = recvfrom(m_socket, data, sizeof(data), MSG_DONTWAIT, NULL, &slen);
|
||||||
|
if (rc <= 0) {
|
||||||
|
logger.error() << "recvfrom failed:" << strerror(errno);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check the IP header
|
||||||
|
const struct iphdr* ip = (struct iphdr*)data;
|
||||||
|
int iphdrlen = ip->ihl * 4;
|
||||||
|
if (rc < iphdrlen || iphdrlen < (int)sizeof(struct iphdr)) {
|
||||||
|
logger.error() << "malformed IP packet:" << strerror(errno);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check the ICMP packet
|
||||||
|
struct icmphdr packet;
|
||||||
|
if (inetChecksum(data + iphdrlen, rc - iphdrlen) != 0) {
|
||||||
|
logger.warning() << "invalid checksum";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (rc >= (iphdrlen + (int)sizeof(packet))) {
|
||||||
|
memcpy(&packet, data + iphdrlen, sizeof(packet));
|
||||||
|
quint16 id = htons(m_ident);
|
||||||
|
if ((packet.type == ICMP_ECHOREPLY) && (packet.un.echo.id == id)) {
|
||||||
|
emit recvPing(htons(packet.un.echo.sequence));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
39
client/platforms/linux/linuxpingsender.h
Normal file
39
client/platforms/linux/linuxpingsender.h
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
#ifndef LINUXPINGSENDER_H
|
||||||
|
#define LINUXPINGSENDER_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
|
||||||
|
#include "../client/mozilla/pingsender.h"
|
||||||
|
|
||||||
|
class QSocketNotifier;
|
||||||
|
|
||||||
|
class LinuxPingSender final : public PingSender {
|
||||||
|
Q_OBJECT
|
||||||
|
Q_DISABLE_COPY_MOVE(LinuxPingSender)
|
||||||
|
|
||||||
|
public:
|
||||||
|
LinuxPingSender(const QHostAddress& source, QObject* parent = nullptr);
|
||||||
|
~LinuxPingSender();
|
||||||
|
|
||||||
|
bool isValid() override { return (m_socket >= 0); };
|
||||||
|
|
||||||
|
void sendPing(const QHostAddress& dest, quint16 sequence) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
int createSocket();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void rawSocketReady();
|
||||||
|
void icmpSocketReady();
|
||||||
|
|
||||||
|
private:
|
||||||
|
QSocketNotifier* m_notifier = nullptr;
|
||||||
|
int m_socket = -1;
|
||||||
|
quint16 m_ident = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // LINUXPINGSENDER_H
|
|
@ -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;
|
||||||
|
|
|
@ -212,6 +212,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
|
||||||
|
@ -226,6 +227,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
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue