mirror of
https://github.com/amnezia-vpn/amnezia-client.git
synced 2026-06-22 02:01:08 +07:00
Compare commits
15 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 89b94d2588 | |||
| 9166e17a23 | |||
| 37d2b8716d | |||
| 92b168100a | |||
| 0f6db8a238 | |||
| 7c075625d2 | |||
| c6a40b09c9 | |||
| 560c4070b4 | |||
| f6806459fd | |||
| 646b1561f8 | |||
| 6d1e10a2e3 | |||
| af0d561c5c | |||
| 214b18f65f | |||
| bd554fb730 | |||
| 316e64122e |
@@ -292,117 +292,103 @@ QPair<QString, QNetworkInterface> NetworkUtilities::getGatewayAndIface()
|
|||||||
return { resGateway, QNetworkInterface::interfaceFromIndex(resIndex) };
|
return { resGateway, QNetworkInterface::interfaceFromIndex(resIndex) };
|
||||||
#endif
|
#endif
|
||||||
#ifdef Q_OS_LINUX
|
#ifdef Q_OS_LINUX
|
||||||
constexpr int BUFFER_SIZE = 100;
|
static constexpr size_t BUFFER_SIZE = 8192;
|
||||||
int received_bytes = 0, msg_len = 0, route_attribute_len = 0;
|
|
||||||
int sock = -1, msgseq = 0;
|
|
||||||
struct nlmsghdr *nlh, *nlmsg;
|
|
||||||
struct rtmsg *route_entry;
|
|
||||||
// This struct contain route attributes (route type)
|
|
||||||
struct rtattr *route_attribute;
|
|
||||||
char gateway_address[INET_ADDRSTRLEN], interface[IF_NAMESIZE];
|
|
||||||
char msgbuf[BUFFER_SIZE], buffer[BUFFER_SIZE];
|
|
||||||
char *ptr = buffer;
|
|
||||||
struct timeval tv;
|
|
||||||
|
|
||||||
if ((sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) < 0) {
|
int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
|
||||||
|
if (sock < 0) {
|
||||||
perror("socket failed");
|
perror("socket failed");
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
memset(msgbuf, 0, sizeof(msgbuf));
|
struct timeval tv { 1, 0 };
|
||||||
memset(gateway_address, 0, sizeof(gateway_address));
|
setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
|
||||||
memset(interface, 0, sizeof(interface));
|
|
||||||
memset(buffer, 0, sizeof(buffer));
|
|
||||||
|
|
||||||
/* point the header and the msg structure pointers into the buffer */
|
struct {
|
||||||
nlmsg = (struct nlmsghdr *)msgbuf;
|
struct nlmsghdr hdr;
|
||||||
|
struct rtmsg rt;
|
||||||
|
} req {};
|
||||||
|
req.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
|
||||||
|
req.hdr.nlmsg_type = RTM_GETROUTE;
|
||||||
|
req.hdr.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST;
|
||||||
|
req.hdr.nlmsg_seq = 1;
|
||||||
|
req.hdr.nlmsg_pid = static_cast<uint32_t>(getpid());
|
||||||
|
req.rt.rtm_family = AF_INET;
|
||||||
|
|
||||||
/* Fill in the nlmsg header*/
|
if (send(sock, &req, req.hdr.nlmsg_len, 0) < 0) {
|
||||||
nlmsg->nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
|
|
||||||
nlmsg->nlmsg_type = RTM_GETROUTE; // Get the routes from kernel routing table .
|
|
||||||
nlmsg->nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST; // The message is a request for dump.
|
|
||||||
nlmsg->nlmsg_seq = msgseq++; // Sequence of the message packet.
|
|
||||||
nlmsg->nlmsg_pid = getpid(); // PID of process sending the request.
|
|
||||||
|
|
||||||
/* 1 Sec Timeout to avoid stall */
|
|
||||||
tv.tv_sec = 1;
|
|
||||||
setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (struct timeval *)&tv, sizeof(struct timeval));
|
|
||||||
/* send msg */
|
|
||||||
if (send(sock, nlmsg, nlmsg->nlmsg_len, 0) < 0) {
|
|
||||||
perror("send failed");
|
perror("send failed");
|
||||||
|
close(sock);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
/* receive response */
|
char buffer[BUFFER_SIZE];
|
||||||
do
|
size_t total_len = 0;
|
||||||
{
|
bool done = false;
|
||||||
received_bytes = recv(sock, ptr, sizeof(buffer) - msg_len, 0);
|
|
||||||
if (received_bytes < 0) {
|
|
||||||
perror("Error in recv");
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
nlh = (struct nlmsghdr *) ptr;
|
while (!done && total_len < BUFFER_SIZE) {
|
||||||
|
ssize_t n = recv(sock, buffer + total_len, BUFFER_SIZE - total_len, 0);
|
||||||
/* Check if the header is valid */
|
if (n <= 0)
|
||||||
if((NLMSG_OK(nlmsg, received_bytes) == 0) ||
|
|
||||||
(nlmsg->nlmsg_type == NLMSG_ERROR))
|
|
||||||
{
|
|
||||||
perror("Error in received packet");
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If we received all data break */
|
|
||||||
if (nlh->nlmsg_type == NLMSG_DONE)
|
|
||||||
break;
|
break;
|
||||||
else {
|
|
||||||
ptr += received_bytes;
|
|
||||||
msg_len += received_bytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Break if its not a multi part message */
|
int scan_len = static_cast<int>(n);
|
||||||
if ((nlmsg->nlmsg_flags & NLM_F_MULTI) == 0)
|
for (struct nlmsghdr *h = reinterpret_cast<struct nlmsghdr *>(buffer + total_len);
|
||||||
break;
|
NLMSG_OK(h, scan_len);
|
||||||
}
|
h = NLMSG_NEXT(h, scan_len))
|
||||||
while ((nlmsg->nlmsg_seq != msgseq) || (nlmsg->nlmsg_pid != getpid()));
|
|
||||||
|
|
||||||
/* parse response */
|
|
||||||
for ( ; NLMSG_OK(nlh, received_bytes); nlh = NLMSG_NEXT(nlh, received_bytes))
|
|
||||||
{
|
|
||||||
/* Get the route data */
|
|
||||||
route_entry = (struct rtmsg *) NLMSG_DATA(nlh);
|
|
||||||
|
|
||||||
/* We are just interested in main routing table */
|
|
||||||
if (route_entry->rtm_table != RT_TABLE_MAIN)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
route_attribute = (struct rtattr *) RTM_RTA(route_entry);
|
|
||||||
route_attribute_len = RTM_PAYLOAD(nlh);
|
|
||||||
|
|
||||||
/* Loop through all attributes */
|
|
||||||
for ( ; RTA_OK(route_attribute, route_attribute_len);
|
|
||||||
route_attribute = RTA_NEXT(route_attribute, route_attribute_len))
|
|
||||||
{
|
{
|
||||||
switch(route_attribute->rta_type) {
|
if (h->nlmsg_type == NLMSG_DONE || h->nlmsg_type == NLMSG_ERROR) {
|
||||||
case RTA_OIF:
|
done = true;
|
||||||
if_indextoname(*(int *)RTA_DATA(route_attribute), interface);
|
|
||||||
break;
|
|
||||||
case RTA_GATEWAY:
|
|
||||||
inet_ntop(AF_INET, RTA_DATA(route_attribute),
|
|
||||||
gateway_address, sizeof(gateway_address));
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
total_len += static_cast<size_t>(n);
|
||||||
if ((*gateway_address) && (*interface)) {
|
|
||||||
qDebug() << "Gateway " << gateway_address << " for interface " << interface;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString resultGw;
|
||||||
|
QString resultIf;
|
||||||
|
int remaining = static_cast<int>(total_len);
|
||||||
|
|
||||||
|
for (struct nlmsghdr *nlh = reinterpret_cast<struct nlmsghdr *>(buffer);
|
||||||
|
NLMSG_OK(nlh, remaining);
|
||||||
|
nlh = NLMSG_NEXT(nlh, remaining))
|
||||||
|
{
|
||||||
|
if (nlh->nlmsg_type == NLMSG_DONE || nlh->nlmsg_type == NLMSG_ERROR)
|
||||||
|
break;
|
||||||
|
if (nlh->nlmsg_type != RTM_NEWROUTE)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
struct rtmsg *rt = static_cast<struct rtmsg *>(NLMSG_DATA(nlh));
|
||||||
|
if (rt->rtm_table != RT_TABLE_MAIN || rt->rtm_family != AF_INET)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
char route_gw[INET_ADDRSTRLEN] = {};
|
||||||
|
char route_if[IF_NAMESIZE] = {};
|
||||||
|
int attr_len = RTM_PAYLOAD(nlh);
|
||||||
|
|
||||||
|
for (struct rtattr *rta = RTM_RTA(rt);
|
||||||
|
RTA_OK(rta, attr_len);
|
||||||
|
rta = RTA_NEXT(rta, attr_len))
|
||||||
|
{
|
||||||
|
if (rta->rta_type == RTA_GATEWAY)
|
||||||
|
inet_ntop(AF_INET, RTA_DATA(rta), route_gw, sizeof(route_gw));
|
||||||
|
else if (rta->rta_type == RTA_OIF)
|
||||||
|
if_indextoname(*static_cast<int *>(RTA_DATA(rta)), route_if);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!route_gw[0] || !route_if[0])
|
||||||
|
continue;
|
||||||
|
|
||||||
|
QString ifStr(route_if);
|
||||||
|
if (ifStr.startsWith(QLatin1String("amn")) ||
|
||||||
|
ifStr.startsWith(QLatin1String("tun")))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
resultGw = QString::fromLatin1(route_gw);
|
||||||
|
resultIf = QString::fromLatin1(route_if);
|
||||||
|
qDebug() << "Gateway " << route_gw << " for interface " << route_if;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
close(sock);
|
close(sock);
|
||||||
return { gateway_address, QNetworkInterface::interfaceFromName(interface) };
|
return { resultGw, QNetworkInterface::interfaceFromName(resultIf) };
|
||||||
#endif
|
#endif
|
||||||
#if defined(Q_OS_MAC) && !defined(Q_OS_IOS) && !defined(MACOS_NE)
|
#if defined(Q_OS_MAC) && !defined(Q_OS_IOS) && !defined(MACOS_NE)
|
||||||
QString gateway;
|
QString gateway;
|
||||||
|
|||||||
@@ -142,10 +142,6 @@ bool Daemon::activate(const InterfaceConfig& config) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!maybeUpdateResolvers(config)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// set routing
|
// set routing
|
||||||
for (const IPAddress& ip : config.m_allowedIPAddressRanges) {
|
for (const IPAddress& ip : config.m_allowedIPAddressRanges) {
|
||||||
if (!wgutils()->updateRoutePrefix(ip)) {
|
if (!wgutils()->updateRoutePrefix(ip)) {
|
||||||
@@ -215,6 +211,11 @@ bool Daemon::addExclusionRoute(const IPAddress& prefix) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (!wgutils()->addExclusionRoute(prefix)) {
|
if (!wgutils()->addExclusionRoute(prefix)) {
|
||||||
|
if (!m_pendingExclusionRoutes.contains(prefix)) {
|
||||||
|
logger.warning() << "Exclusion route deferred (no gateway):"
|
||||||
|
<< prefix.toString();
|
||||||
|
m_pendingExclusionRoutes.append(prefix);
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
m_excludedAddrSet[prefix] = 1;
|
m_excludedAddrSet[prefix] = 1;
|
||||||
@@ -480,6 +481,7 @@ bool Daemon::deactivate(bool emitSignals) {
|
|||||||
wgutils()->deleteExclusionRoute(iterator.key());
|
wgutils()->deleteExclusionRoute(iterator.key());
|
||||||
}
|
}
|
||||||
m_excludedAddrSet.clear();
|
m_excludedAddrSet.clear();
|
||||||
|
m_pendingExclusionRoutes.clear();
|
||||||
|
|
||||||
m_connections.clear();
|
m_connections.clear();
|
||||||
// Delete the interface
|
// Delete the interface
|
||||||
@@ -589,6 +591,19 @@ void Daemon::checkHandshake() {
|
|||||||
|
|
||||||
logger.debug() << "Checking for handshake...";
|
logger.debug() << "Checking for handshake...";
|
||||||
|
|
||||||
|
if (!m_pendingExclusionRoutes.isEmpty()) {
|
||||||
|
QList<IPAddress> stillPending;
|
||||||
|
for (const IPAddress& prefix : m_pendingExclusionRoutes) {
|
||||||
|
if (!wgutils()->addExclusionRoute(prefix)) {
|
||||||
|
stillPending.append(prefix);
|
||||||
|
} else {
|
||||||
|
logger.debug() << "Deferred exclusion route added:" << prefix.toString();
|
||||||
|
m_excludedAddrSet[prefix] = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m_pendingExclusionRoutes = stillPending;
|
||||||
|
}
|
||||||
|
|
||||||
int pendingHandshakes = 0;
|
int pendingHandshakes = 0;
|
||||||
QList<WireguardUtils::PeerStatus> peers = wgutils()->getPeerStatus();
|
QList<WireguardUtils::PeerStatus> peers = wgutils()->getPeerStatus();
|
||||||
for (ConnectionState& connection : m_connections) {
|
for (ConnectionState& connection : m_connections) {
|
||||||
@@ -605,6 +620,7 @@ void Daemon::checkHandshake() {
|
|||||||
}
|
}
|
||||||
if (status.m_handshake != 0) {
|
if (status.m_handshake != 0) {
|
||||||
connection.m_date.setMSecsSinceEpoch(status.m_handshake);
|
connection.m_date.setMSecsSinceEpoch(status.m_handshake);
|
||||||
|
maybeUpdateResolvers(config);
|
||||||
emit connected(status.m_pubkey);
|
emit connected(status.m_pubkey);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -87,6 +87,7 @@ class Daemon : public QObject {
|
|||||||
};
|
};
|
||||||
QMap<InterfaceConfig::HopType, ConnectionState> m_connections;
|
QMap<InterfaceConfig::HopType, ConnectionState> m_connections;
|
||||||
QHash<IPAddress, int> m_excludedAddrSet;
|
QHash<IPAddress, int> m_excludedAddrSet;
|
||||||
|
QList<IPAddress> m_pendingExclusionRoutes;
|
||||||
QTimer m_handshakeTimer;
|
QTimer m_handshakeTimer;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -4,20 +4,14 @@
|
|||||||
|
|
||||||
#include "dnsutilslinux.h"
|
#include "dnsutilslinux.h"
|
||||||
|
|
||||||
#include <net/if.h>
|
#include <QDir>
|
||||||
|
#include <QFile>
|
||||||
#include <QDBusVariant>
|
#include <QFileInfo>
|
||||||
#include <QtDBus/QtDBus>
|
#include <QProcess>
|
||||||
|
|
||||||
#include "leakdetector.h"
|
#include "leakdetector.h"
|
||||||
#include "logger.h"
|
#include "logger.h"
|
||||||
|
|
||||||
constexpr const char* DBUS_RESOLVE_SERVICE = "org.freedesktop.resolve1";
|
|
||||||
constexpr const char* DBUS_RESOLVE_PATH = "/org/freedesktop/resolve1";
|
|
||||||
constexpr const char* DBUS_RESOLVE_MANAGER = "org.freedesktop.resolve1.Manager";
|
|
||||||
constexpr const char* DBUS_PROPERTY_INTERFACE =
|
|
||||||
"org.freedesktop.DBus.Properties";
|
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
Logger logger("DnsUtilsLinux");
|
Logger logger("DnsUtilsLinux");
|
||||||
}
|
}
|
||||||
@@ -25,188 +19,147 @@ Logger logger("DnsUtilsLinux");
|
|||||||
DnsUtilsLinux::DnsUtilsLinux(QObject* parent) : DnsUtils(parent) {
|
DnsUtilsLinux::DnsUtilsLinux(QObject* parent) : DnsUtils(parent) {
|
||||||
MZ_COUNT_CTOR(DnsUtilsLinux);
|
MZ_COUNT_CTOR(DnsUtilsLinux);
|
||||||
logger.debug() << "DnsUtilsLinux created.";
|
logger.debug() << "DnsUtilsLinux created.";
|
||||||
|
|
||||||
QDBusConnection conn = QDBusConnection::systemBus();
|
|
||||||
m_resolver = new QDBusInterface(DBUS_RESOLVE_SERVICE, DBUS_RESOLVE_PATH,
|
|
||||||
DBUS_RESOLVE_MANAGER, conn, this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DnsUtilsLinux::~DnsUtilsLinux() {
|
DnsUtilsLinux::~DnsUtilsLinux() {
|
||||||
MZ_COUNT_DTOR(DnsUtilsLinux);
|
MZ_COUNT_DTOR(DnsUtilsLinux);
|
||||||
|
|
||||||
for (auto iterator = m_linkDomains.constBegin();
|
|
||||||
iterator != m_linkDomains.constEnd(); ++iterator) {
|
|
||||||
QList<QVariant> argumentList;
|
|
||||||
argumentList << QVariant::fromValue(iterator.key());
|
|
||||||
argumentList << QVariant::fromValue(iterator.value());
|
|
||||||
m_resolver->asyncCallWithArgumentList(QStringLiteral("SetLinkDomains"),
|
|
||||||
argumentList);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_ifindex > 0) {
|
|
||||||
m_resolver->asyncCall(QStringLiteral("RevertLink"), m_ifindex);
|
|
||||||
}
|
|
||||||
|
|
||||||
logger.debug() << "DnsUtilsLinux destroyed.";
|
logger.debug() << "DnsUtilsLinux destroyed.";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DnsUtilsLinux::writeResolvConf(const QList<QHostAddress>& resolvers) {
|
||||||
|
if (resolvers.isEmpty()) return;
|
||||||
|
|
||||||
|
static const QString kPath = QStringLiteral("/etc/resolv.conf");
|
||||||
|
|
||||||
|
if (m_resolvConfOriginal.isEmpty()) {
|
||||||
|
QFileInfo fi(kPath);
|
||||||
|
if (fi.isSymLink()) {
|
||||||
|
m_resolvConfOriginal = fi.symLinkTarget();
|
||||||
|
logger.debug() << "Saved resolv.conf symlink target:"
|
||||||
|
<< m_resolvConfOriginal;
|
||||||
|
if (!m_stateFilePath.isEmpty()) {
|
||||||
|
QFile sf(m_stateFilePath);
|
||||||
|
if (sf.open(QIODevice::WriteOnly | QIODevice::Text))
|
||||||
|
sf.write(m_resolvConfOriginal.toUtf8());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
QFile orig(kPath);
|
||||||
|
if (orig.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||||
|
QByteArray content = orig.readAll();
|
||||||
|
orig.close();
|
||||||
|
m_resolvConfOriginal = QStringLiteral("__file__");
|
||||||
|
logger.debug() << "resolv.conf is a regular file; saved content for restore";
|
||||||
|
if (!m_stateFilePath.isEmpty()) {
|
||||||
|
QFile sf(m_stateFilePath);
|
||||||
|
if (sf.open(QIODevice::WriteOnly | QIODevice::Text)) {
|
||||||
|
sf.write("__file__:");
|
||||||
|
sf.write(content);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
m_resolvConfOriginal = QStringLiteral("__file__");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QFile::remove(kPath);
|
||||||
|
QFile f(kPath);
|
||||||
|
if (!f.open(QIODevice::WriteOnly | QIODevice::Text)) {
|
||||||
|
logger.warning() << "Failed to write" << kPath << ":" << f.errorString();
|
||||||
|
if (m_resolvConfOriginal != QStringLiteral("__file__"))
|
||||||
|
QFile::link(m_resolvConfOriginal, kPath);
|
||||||
|
m_resolvConfOriginal.clear();
|
||||||
|
if (!m_stateFilePath.isEmpty()) QFile::remove(m_stateFilePath);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (const auto& r : resolvers) {
|
||||||
|
if (r.protocol() == QAbstractSocket::IPv4Protocol)
|
||||||
|
f.write(
|
||||||
|
QStringLiteral("nameserver %1\n").arg(r.toString()).toUtf8());
|
||||||
|
}
|
||||||
|
f.close();
|
||||||
|
logger.debug() << "Wrote resolv.conf with" << resolvers.size()
|
||||||
|
<< "DNS servers";
|
||||||
|
}
|
||||||
|
|
||||||
|
void DnsUtilsLinux::restoreResolvConf() {
|
||||||
|
if (m_resolvConfOriginal.isEmpty()) return;
|
||||||
|
|
||||||
|
const QString original = m_resolvConfOriginal;
|
||||||
|
m_resolvConfOriginal.clear();
|
||||||
|
|
||||||
|
if (!m_stateFilePath.isEmpty())
|
||||||
|
QFile::remove(m_stateFilePath);
|
||||||
|
|
||||||
|
static const char* kPath = "/etc/resolv.conf";
|
||||||
|
|
||||||
|
QFile::remove(kPath);
|
||||||
|
|
||||||
|
if (original == QStringLiteral("__file__")) {
|
||||||
|
if (!m_resolvConfSavedContent.isEmpty()) {
|
||||||
|
QFile f(kPath);
|
||||||
|
if (f.open(QIODevice::WriteOnly | QIODevice::Text)) {
|
||||||
|
f.write(m_resolvConfSavedContent.toUtf8());
|
||||||
|
logger.debug() << "Restored resolv.conf from saved content";
|
||||||
|
}
|
||||||
|
m_resolvConfSavedContent.clear();
|
||||||
|
} else if (QFile::exists(QStringLiteral("/run/systemd/resolve/stub-resolv.conf"))) {
|
||||||
|
QFile::link(QStringLiteral("/run/systemd/resolve/stub-resolv.conf"), kPath);
|
||||||
|
logger.debug() << "Restored resolv.conf symlink to stub-resolv.conf";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
QFile::link(original, kPath);
|
||||||
|
logger.debug() << "Restored resolv.conf symlink to" << original;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool DnsUtilsLinux::updateResolvers(const QString& ifname,
|
bool DnsUtilsLinux::updateResolvers(const QString& ifname,
|
||||||
const QList<QHostAddress>& resolvers) {
|
const QList<QHostAddress>& resolvers) {
|
||||||
m_ifindex = if_nametoindex(qPrintable(ifname));
|
m_stateFilePath = QStringLiteral("/run/amnezia-dns-%1").arg(ifname);
|
||||||
if (m_ifindex <= 0) {
|
|
||||||
logger.error() << "Unable to resolve ifindex for" << ifname;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
setLinkDNS(m_ifindex, resolvers);
|
writeResolvConf(resolvers);
|
||||||
setLinkDefaultRoute(m_ifindex, true);
|
|
||||||
updateLinkDomains();
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DnsUtilsLinux::restoreResolvers() {
|
bool DnsUtilsLinux::restoreResolvers() {
|
||||||
for (auto iterator = m_linkDomains.constBegin();
|
|
||||||
iterator != m_linkDomains.constEnd(); ++iterator) {
|
if (m_resolvConfOriginal.isEmpty()) {
|
||||||
setLinkDomains(iterator.key(), iterator.value());
|
QStringList candidates;
|
||||||
|
if (!m_stateFilePath.isEmpty()) {
|
||||||
|
candidates << m_stateFilePath;
|
||||||
|
} else {
|
||||||
|
|
||||||
|
QDir runDir(QStringLiteral("/run"));
|
||||||
|
for (const QString& name : runDir.entryList(
|
||||||
|
{QStringLiteral("amnezia-dns-*")}, QDir::Files)) {
|
||||||
|
candidates << runDir.filePath(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (const QString& path : candidates) {
|
||||||
|
QFile sf(path);
|
||||||
|
if (sf.open(QIODevice::ReadOnly)) {
|
||||||
|
QByteArray data = sf.readAll();
|
||||||
|
sf.close();
|
||||||
|
m_stateFilePath = path;
|
||||||
|
if (data.startsWith("__file__:")) {
|
||||||
|
m_resolvConfOriginal = QStringLiteral("__file__");
|
||||||
|
m_resolvConfSavedContent = QString::fromUtf8(data.mid(9));
|
||||||
|
} else {
|
||||||
|
m_resolvConfOriginal = QString::fromUtf8(data).trimmed();
|
||||||
|
}
|
||||||
|
logger.debug() << "Recovered DNS original from" << path << ":"
|
||||||
|
<< m_resolvConfOriginal;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
m_linkDomains.clear();
|
|
||||||
|
|
||||||
/* Revert the VPN interface's DNS configuration */
|
const bool hadDnsState = !m_resolvConfOriginal.isEmpty();
|
||||||
if (m_ifindex > 0) {
|
restoreResolvConf();
|
||||||
QList<QVariant> argumentList = {QVariant::fromValue(m_ifindex)};
|
|
||||||
QDBusPendingReply<> reply = m_resolver->asyncCallWithArgumentList(
|
|
||||||
QStringLiteral("RevertLink"), argumentList);
|
|
||||||
|
|
||||||
QDBusPendingCallWatcher* watcher = new QDBusPendingCallWatcher(reply, this);
|
if (hadDnsState && QFile::exists(QStringLiteral("/run/systemd/resolve"))) {
|
||||||
QObject::connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), this,
|
QProcess::startDetached("systemctl", {"restart", "systemd-resolved"});
|
||||||
SLOT(dnsCallCompleted(QDBusPendingCallWatcher*)));
|
|
||||||
|
|
||||||
m_ifindex = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DnsUtilsLinux::dnsCallCompleted(QDBusPendingCallWatcher* call) {
|
|
||||||
QDBusPendingReply<> reply = *call;
|
|
||||||
if (reply.isError()) {
|
|
||||||
logger.error() << "Error received from the DBus service";
|
|
||||||
}
|
|
||||||
delete call;
|
|
||||||
}
|
|
||||||
|
|
||||||
void DnsUtilsLinux::setLinkDNS(int ifindex,
|
|
||||||
const QList<QHostAddress>& resolvers) {
|
|
||||||
QList<DnsResolver> resolverList;
|
|
||||||
char ifnamebuf[IF_NAMESIZE];
|
|
||||||
const char* ifname = if_indextoname(ifindex, ifnamebuf);
|
|
||||||
for (const auto& ip : resolvers) {
|
|
||||||
resolverList.append(ip);
|
|
||||||
if (ifname) {
|
|
||||||
logger.debug() << "Adding DNS resolver" << ip.toString() << "via"
|
|
||||||
<< ifname;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
QList<QVariant> argumentList;
|
|
||||||
argumentList << QVariant::fromValue(ifindex);
|
|
||||||
argumentList << QVariant::fromValue(resolverList);
|
|
||||||
QDBusPendingReply<> reply = m_resolver->asyncCallWithArgumentList(
|
|
||||||
QStringLiteral("SetLinkDNS"), argumentList);
|
|
||||||
|
|
||||||
QDBusPendingCallWatcher* watcher = new QDBusPendingCallWatcher(reply, this);
|
|
||||||
QObject::connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), this,
|
|
||||||
SLOT(dnsCallCompleted(QDBusPendingCallWatcher*)));
|
|
||||||
}
|
|
||||||
|
|
||||||
void DnsUtilsLinux::setLinkDomains(int ifindex,
|
|
||||||
const QList<DnsLinkDomain>& domains) {
|
|
||||||
char ifnamebuf[IF_NAMESIZE];
|
|
||||||
const char* ifname = if_indextoname(ifindex, ifnamebuf);
|
|
||||||
if (ifname) {
|
|
||||||
for (const auto& d : domains) {
|
|
||||||
// The DNS search domains often winds up revealing user's ISP which
|
|
||||||
// can correlate back to their location.
|
|
||||||
logger.debug() << "Setting DNS domain:" << logger.sensitive(d.domain)
|
|
||||||
<< "via" << ifname << (d.search ? "search" : "");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
QList<QVariant> argumentList;
|
|
||||||
argumentList << QVariant::fromValue(ifindex);
|
|
||||||
argumentList << QVariant::fromValue(domains);
|
|
||||||
QDBusPendingReply<> reply = m_resolver->asyncCallWithArgumentList(
|
|
||||||
QStringLiteral("SetLinkDomains"), argumentList);
|
|
||||||
|
|
||||||
QDBusPendingCallWatcher* watcher = new QDBusPendingCallWatcher(reply, this);
|
|
||||||
QObject::connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), this,
|
|
||||||
SLOT(dnsCallCompleted(QDBusPendingCallWatcher*)));
|
|
||||||
}
|
|
||||||
|
|
||||||
void DnsUtilsLinux::setLinkDefaultRoute(int ifindex, bool enable) {
|
|
||||||
QList<QVariant> argumentList;
|
|
||||||
argumentList << QVariant::fromValue(ifindex);
|
|
||||||
argumentList << QVariant::fromValue(enable);
|
|
||||||
QDBusPendingReply<> reply = m_resolver->asyncCallWithArgumentList(
|
|
||||||
QStringLiteral("SetLinkDefaultRoute"), argumentList);
|
|
||||||
|
|
||||||
QDBusPendingCallWatcher* watcher = new QDBusPendingCallWatcher(reply, this);
|
|
||||||
QObject::connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), this,
|
|
||||||
SLOT(dnsCallCompleted(QDBusPendingCallWatcher*)));
|
|
||||||
}
|
|
||||||
|
|
||||||
void DnsUtilsLinux::updateLinkDomains() {
|
|
||||||
/* Get the list of search domains, and remove any others that might conspire
|
|
||||||
* to satisfy DNS resolution. Unfortunately, this is a pain because Qt doesn't
|
|
||||||
* seem to be able to demarshall complex property types.
|
|
||||||
*/
|
|
||||||
QDBusMessage message = QDBusMessage::createMethodCall(
|
|
||||||
DBUS_RESOLVE_SERVICE, DBUS_RESOLVE_PATH, DBUS_PROPERTY_INTERFACE, "Get");
|
|
||||||
message << QString(DBUS_RESOLVE_MANAGER);
|
|
||||||
message << QString("Domains");
|
|
||||||
QDBusPendingReply<QVariant> reply =
|
|
||||||
m_resolver->connection().asyncCall(message);
|
|
||||||
|
|
||||||
QDBusPendingCallWatcher* watcher = new QDBusPendingCallWatcher(reply, this);
|
|
||||||
QObject::connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), this,
|
|
||||||
SLOT(dnsDomainsReceived(QDBusPendingCallWatcher*)));
|
|
||||||
}
|
|
||||||
|
|
||||||
void DnsUtilsLinux::dnsDomainsReceived(QDBusPendingCallWatcher* call) {
|
|
||||||
QDBusPendingReply<QVariant> reply = *call;
|
|
||||||
if (reply.isError()) {
|
|
||||||
logger.error() << "Error retrieving the DNS domains from the DBus service";
|
|
||||||
delete call;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Update the state of the DNS domains */
|
|
||||||
m_linkDomains.clear();
|
|
||||||
QDBusArgument args = qvariant_cast<QDBusArgument>(reply.value());
|
|
||||||
QList<DnsDomain> list = qdbus_cast<QList<DnsDomain>>(args);
|
|
||||||
for (const auto& d : list) {
|
|
||||||
if (d.ifindex == 0) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
m_linkDomains[d.ifindex].append(DnsLinkDomain(d.domain, d.search));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Drop any competing root search domains. */
|
|
||||||
DnsLinkDomain root = DnsLinkDomain(".", true);
|
|
||||||
for (auto iterator = m_linkDomains.constBegin();
|
|
||||||
iterator != m_linkDomains.constEnd(); ++iterator) {
|
|
||||||
if (!iterator.value().contains(root)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
QList<DnsLinkDomain> newlist = iterator.value();
|
|
||||||
newlist.removeAll(root);
|
|
||||||
setLinkDomains(iterator.key(), newlist);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Add a root search domain for the new interface. */
|
|
||||||
QList<DnsLinkDomain> newlist = {root};
|
|
||||||
setLinkDomains(m_ifindex, newlist);
|
|
||||||
delete call;
|
|
||||||
}
|
|
||||||
|
|
||||||
static DnsMetatypeRegistrationProxy s_dnsMetatypeProxy;
|
|
||||||
|
|||||||
@@ -5,11 +5,11 @@
|
|||||||
#ifndef DNSUTILSLINUX_H
|
#ifndef DNSUTILSLINUX_H
|
||||||
#define DNSUTILSLINUX_H
|
#define DNSUTILSLINUX_H
|
||||||
|
|
||||||
#include <QDBusInterface>
|
#include <QHostAddress>
|
||||||
#include <QDBusPendingCallWatcher>
|
#include <QList>
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
#include "daemon/dnsutils.h"
|
#include "daemon/dnsutils.h"
|
||||||
#include "dbustypeslinux.h"
|
|
||||||
|
|
||||||
class DnsUtilsLinux final : public DnsUtils {
|
class DnsUtilsLinux final : public DnsUtils {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
@@ -23,19 +23,14 @@ class DnsUtilsLinux final : public DnsUtils {
|
|||||||
bool restoreResolvers() override;
|
bool restoreResolvers() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void setLinkDNS(int ifindex, const QList<QHostAddress>& resolvers);
|
void writeResolvConf(const QList<QHostAddress>& resolvers);
|
||||||
void setLinkDomains(int ifindex, const QList<DnsLinkDomain>& domains);
|
void restoreResolvConf();
|
||||||
void setLinkDefaultRoute(int ifindex, bool enable);
|
|
||||||
void updateLinkDomains();
|
|
||||||
|
|
||||||
private slots:
|
|
||||||
void dnsCallCompleted(QDBusPendingCallWatcher*);
|
|
||||||
void dnsDomainsReceived(QDBusPendingCallWatcher*);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int m_ifindex = 0;
|
|
||||||
QMap<int, DnsLinkDomainList> m_linkDomains;
|
QString m_resolvConfOriginal;
|
||||||
QDBusInterface* m_resolver = nullptr;
|
QString m_resolvConfSavedContent;
|
||||||
|
QString m_stateFilePath;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // DNSUTILSLINUX_H
|
#endif
|
||||||
|
|||||||
@@ -32,6 +32,7 @@
|
|||||||
|
|
||||||
#include "linuxfirewall.h"
|
#include "linuxfirewall.h"
|
||||||
#include "logger.h"
|
#include "logger.h"
|
||||||
|
#include <QHostAddress>
|
||||||
#include <QProcess>
|
#include <QProcess>
|
||||||
|
|
||||||
#define BRAND_CODE "amn"
|
#define BRAND_CODE "amn"
|
||||||
@@ -108,7 +109,7 @@ int LinuxFirewall::linkChain(LinuxFirewall::IPVersion ip, const QString& chain,
|
|||||||
// (we can't safely delete all rules at once since rule numbers change)
|
// (we can't safely delete all rules at once since rule numbers change)
|
||||||
// TODO: occasionally this script results in warnings in logs "Bad rule (does a matching rule exist in the chain?)" - this happens when
|
// TODO: occasionally this script results in warnings in logs "Bad rule (does a matching rule exist in the chain?)" - this happens when
|
||||||
// the e.g OUTPUT chain is empty but this script attempts to delete things from it anyway. It doesn't cause any problems, but we should still fix at some point..
|
// the e.g OUTPUT chain is empty but this script attempts to delete things from it anyway. It doesn't cause any problems, but we should still fix at some point..
|
||||||
return execute(QStringLiteral("if ! %1 -L %2 -n --line-numbers -t %4 2> /dev/null | awk 'int($1) == 1 && $2 == \"%3\" { found=1 } END { if(found==1) { exit 0 } else { exit 1 } }' ; then %1 -I %2 -j %3 -t %4 && %1 -L %2 -n --line-numbers -t %4 2> /dev/null | awk 'int($1) > 1 && $2 == \"%3\" { print $1; exit }' | xargs %1 -t %4 -D %2 ; fi").arg(cmd, parent, chain, tableName));
|
return execute(QStringLiteral("if ! %1 -L %2 -n --line-numbers -t %4 2> /dev/null | awk 'int($1) == 1 && $2 == \"%3\" { found=1 } END { if(found==1) { exit 0 } else { exit 1 } }' ; then %1 -I %2 -j %3 -t %4 && %1 -L %2 -n --line-numbers -t %4 2> /dev/null | awk 'int($1) > 1 && $2 == \"%3\" { print $1; exit }' | xargs -r %1 -t %4 -D %2 ; fi").arg(cmd, parent, chain, tableName));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
return execute(QStringLiteral("if ! %1 -C %2 -j %3 -t %4 2> /dev/null ; then %1 -A %2 -j %3 -t %4; fi").arg(cmd, parent, chain, tableName));
|
return execute(QStringLiteral("if ! %1 -C %2 -j %3 -t %4 2> /dev/null ; then %1 -A %2 -j %3 -t %4; fi").arg(cmd, parent, chain, tableName));
|
||||||
@@ -192,12 +193,8 @@ QStringList LinuxFirewall::getDNSRules(const QStringList& servers)
|
|||||||
QStringList result;
|
QStringList result;
|
||||||
for (const QString& server : servers)
|
for (const QString& server : servers)
|
||||||
{
|
{
|
||||||
result << QStringLiteral("-o amn0+ -d %1 -p udp --dport 53 -j ACCEPT").arg(server);
|
result << QStringLiteral("-d %1 -p udp --dport 53 -j ACCEPT").arg(server);
|
||||||
result << QStringLiteral("-o amn0+ -d %1 -p tcp --dport 53 -j ACCEPT").arg(server);
|
result << QStringLiteral("-d %1 -p tcp --dport 53 -j ACCEPT").arg(server);
|
||||||
result << QStringLiteral("-o tun0+ -d %1 -p udp --dport 53 -j ACCEPT").arg(server);
|
|
||||||
result << QStringLiteral("-o tun0+ -d %1 -p tcp --dport 53 -j ACCEPT").arg(server);
|
|
||||||
result << QStringLiteral("-o tun2+ -d %1 -p udp --dport 53 -j ACCEPT").arg(server);
|
|
||||||
result << QStringLiteral("-o tun2+ -d %1 -p tcp --dport 53 -j ACCEPT").arg(server);
|
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -245,7 +242,7 @@ void LinuxFirewall::install()
|
|||||||
QStringLiteral("-o lo+ -j ACCEPT"),
|
QStringLiteral("-o lo+ -j ACCEPT"),
|
||||||
});
|
});
|
||||||
|
|
||||||
installAnchor(IPv4, QStringLiteral("320.allowDNS"), {});
|
installAnchor(Both, QStringLiteral("320.allowDNS"), {});
|
||||||
|
|
||||||
installAnchor(Both, QStringLiteral("310.blockDNS"), {
|
installAnchor(Both, QStringLiteral("310.blockDNS"), {
|
||||||
QStringLiteral("-p udp --dport 53 -j REJECT"),
|
QStringLiteral("-p udp --dport 53 -j REJECT"),
|
||||||
@@ -289,6 +286,7 @@ void LinuxFirewall::install()
|
|||||||
installAnchor(Both, QStringLiteral("100.blockAll"), {
|
installAnchor(Both, QStringLiteral("100.blockAll"), {
|
||||||
QStringLiteral("-j REJECT"),
|
QStringLiteral("-j REJECT"),
|
||||||
});
|
});
|
||||||
|
installAnchor(Both, QStringLiteral("400.allowPIA"), {});
|
||||||
// NAT rules
|
// NAT rules
|
||||||
installAnchor(Both, QStringLiteral("100.transIp"), {
|
installAnchor(Both, QStringLiteral("100.transIp"), {
|
||||||
|
|
||||||
@@ -351,7 +349,7 @@ void LinuxFirewall::uninstall()
|
|||||||
// Remove filter anchors
|
// Remove filter anchors
|
||||||
uninstallAnchor(Both, QStringLiteral("000.allowLoopback"));
|
uninstallAnchor(Both, QStringLiteral("000.allowLoopback"));
|
||||||
uninstallAnchor(Both, QStringLiteral("400.allowPIA"));
|
uninstallAnchor(Both, QStringLiteral("400.allowPIA"));
|
||||||
uninstallAnchor(IPv4, QStringLiteral("320.allowDNS"));
|
uninstallAnchor(Both, QStringLiteral("320.allowDNS"));
|
||||||
uninstallAnchor(Both, QStringLiteral("310.blockDNS"));
|
uninstallAnchor(Both, QStringLiteral("310.blockDNS"));
|
||||||
uninstallAnchor(Both, QStringLiteral("300.allowLAN"));
|
uninstallAnchor(Both, QStringLiteral("300.allowLAN"));
|
||||||
uninstallAnchor(Both, QStringLiteral("290.allowDHCP"));
|
uninstallAnchor(Both, QStringLiteral("290.allowDHCP"));
|
||||||
@@ -372,6 +370,8 @@ void LinuxFirewall::uninstall()
|
|||||||
|
|
||||||
teardownTrafficSplitting();
|
teardownTrafficSplitting();
|
||||||
|
|
||||||
|
anchorCallbacks.clear();
|
||||||
|
|
||||||
logger.debug() << "LinuxFirewall::uninstall() complete";
|
logger.debug() << "LinuxFirewall::uninstall() complete";
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -445,12 +445,17 @@ void LinuxFirewall::setAnchorEnabled(LinuxFirewall::IPVersion ip, const QString
|
|||||||
|
|
||||||
void LinuxFirewall::updateDNSServers(const QStringList& servers)
|
void LinuxFirewall::updateDNSServers(const QStringList& servers)
|
||||||
{
|
{
|
||||||
static QStringList existingServers {};
|
|
||||||
|
|
||||||
existingServers = servers;
|
|
||||||
execute(QStringLiteral("iptables -F %1.320.allowDNS").arg(kAnchorName));
|
execute(QStringLiteral("iptables -F %1.320.allowDNS").arg(kAnchorName));
|
||||||
for (const QString& rule : getDNSRules(servers))
|
execute(QStringLiteral("ip6tables -F %1.320.allowDNS").arg(kAnchorName));
|
||||||
execute(QStringLiteral("iptables -A %1.320.allowDNS %2").arg(kAnchorName, rule));
|
|
||||||
|
for (const QString& server : servers) {
|
||||||
|
if (server.isEmpty()) continue;
|
||||||
|
const QString cmd = (QHostAddress(server).protocol() == QAbstractSocket::IPv6Protocol)
|
||||||
|
? QStringLiteral("ip6tables")
|
||||||
|
: QStringLiteral("iptables");
|
||||||
|
execute(QStringLiteral("%1 -A %2.320.allowDNS -d %3 -p udp --dport 53 -j ACCEPT").arg(cmd, kAnchorName, server));
|
||||||
|
execute(QStringLiteral("%1 -A %2.320.allowDNS -d %3 -p tcp --dport 53 -j ACCEPT").arg(cmd, kAnchorName, server));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void LinuxFirewall::updateAllowNets(const QStringList& servers)
|
void LinuxFirewall::updateAllowNets(const QStringList& servers)
|
||||||
@@ -495,13 +500,20 @@ int LinuxFirewall::execute(const QString &command, bool ignoreErrors)
|
|||||||
logger.debug() << "(" << exitCode << ") $ " << command;
|
logger.debug() << "(" << exitCode << ") $ " << command;
|
||||||
if (!out.isEmpty())
|
if (!out.isEmpty())
|
||||||
logger.info() << out;
|
logger.info() << out;
|
||||||
if (!err.isEmpty())
|
if (!err.isEmpty() && !ignoreErrors)
|
||||||
logger.warning() << err;
|
logger.warning() << err;
|
||||||
return exitCode;
|
return exitCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
void LinuxFirewall::setupTrafficSplitting()
|
void LinuxFirewall::setupTrafficSplitting()
|
||||||
{
|
{
|
||||||
|
execute(QStringLiteral("grep -q '%1' /etc/iproute2/rt_tables || printf '200\\t%1\\n' >> /etc/iproute2/rt_tables").arg(kRtableName));
|
||||||
|
|
||||||
|
execute(QStringLiteral(
|
||||||
|
"if [ ! -d /sys/fs/cgroup/net_cls ] ; then "
|
||||||
|
"mkdir -p /sys/fs/cgroup/net_cls && "
|
||||||
|
"mount -t cgroup -o net_cls cgroup /sys/fs/cgroup/net_cls ; fi"));
|
||||||
|
|
||||||
auto cGroupDir = "/sys/fs/cgroup/net_cls/" BRAND_CODE "vpnexclusions/";
|
auto cGroupDir = "/sys/fs/cgroup/net_cls/" BRAND_CODE "vpnexclusions/";
|
||||||
logger.info() << "Should be setting up cgroup in" << cGroupDir << "for traffic splitting";
|
logger.info() << "Should be setting up cgroup in" << cGroupDir << "for traffic splitting";
|
||||||
execute(QStringLiteral("if [ ! -d %1 ] ; then mkdir %1 ; sleep 0.1 ; echo %2 > %1/net_cls.classid ; fi").arg(cGroupDir).arg(kCGroupId));
|
execute(QStringLiteral("if [ ! -d %1 ] ; then mkdir %1 ; sleep 0.1 ; echo %2 > %1/net_cls.classid ; fi").arg(cGroupDir).arg(kCGroupId));
|
||||||
@@ -513,6 +525,7 @@ void LinuxFirewall::teardownTrafficSplitting()
|
|||||||
{
|
{
|
||||||
logger.info() << "Tearing down cgroup and routing rules";
|
logger.info() << "Tearing down cgroup and routing rules";
|
||||||
execute(QStringLiteral("if ip rule list | grep -q %1; then ip rule del from all fwmark %1 lookup %2 2> /dev/null ; fi").arg(kPacketTag, kRtableName));
|
execute(QStringLiteral("if ip rule list | grep -q %1; then ip rule del from all fwmark %1 lookup %2 2> /dev/null ; fi").arg(kPacketTag, kRtableName));
|
||||||
execute(QStringLiteral("ip route flush table %1").arg(kRtableName));
|
execute(QStringLiteral("ip route flush table %1").arg(kRtableName), true);
|
||||||
execute(QStringLiteral("ip route flush cache"));
|
execute(QStringLiteral("ip route flush cache"));
|
||||||
|
execute(QStringLiteral("sed -i '/%1/d' /etc/iproute2/rt_tables").arg(kRtableName));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -164,8 +164,13 @@ bool LinuxRouteMonitor::rtmSendRoute(int action, int flags, int type,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (rtm->rtm_type == RTN_THROW) {
|
if (rtm->rtm_type == RTN_THROW) {
|
||||||
|
QString gateway = NetworkUtilities::getGatewayAndIface().first;
|
||||||
|
if (gateway.isEmpty()) {
|
||||||
|
logger.warning() << "No default gateway available, skipping exclusion route";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
struct in_addr ip4;
|
struct in_addr ip4;
|
||||||
inet_pton(AF_INET, NetworkUtilities::getGatewayAndIface().first.toUtf8(), &ip4);
|
inet_pton(AF_INET, gateway.toUtf8(), &ip4);
|
||||||
nlmsg_append_attr(nlmsg, sizeof(buf), RTA_GATEWAY, &ip4, sizeof(ip4));
|
nlmsg_append_attr(nlmsg, sizeof(buf), RTA_GATEWAY, &ip4, sizeof(ip4));
|
||||||
nlmsg_append_attr32(nlmsg, sizeof(buf), RTA_PRIORITY, 0);
|
nlmsg_append_attr32(nlmsg, sizeof(buf), RTA_PRIORITY, 0);
|
||||||
rtm->rtm_type = RTN_UNICAST;
|
rtm->rtm_type = RTN_UNICAST;
|
||||||
|
|||||||
@@ -44,6 +44,9 @@ void LinuxNetworkWatcher::initialize() {
|
|||||||
connect(m_worker, &LinuxNetworkWatcherWorker::wakeup, this,
|
connect(m_worker, &LinuxNetworkWatcherWorker::wakeup, this,
|
||||||
&NetworkWatcherImpl::wakeup);
|
&NetworkWatcherImpl::wakeup);
|
||||||
|
|
||||||
|
connect(m_worker, &LinuxNetworkWatcherWorker::networkChanged, this,
|
||||||
|
[this]() { emit networkChanged(""); });
|
||||||
|
|
||||||
// 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
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
#include "linuxnetworkwatcherworker.h"
|
#include "linuxnetworkwatcherworker.h"
|
||||||
|
|
||||||
|
#include <QTimer>
|
||||||
#include <QtDBus/QtDBus>
|
#include <QtDBus/QtDBus>
|
||||||
|
|
||||||
#include "leakdetector.h"
|
#include "leakdetector.h"
|
||||||
@@ -37,6 +38,7 @@
|
|||||||
enum NMState {
|
enum NMState {
|
||||||
NM_STATE_UNKNOWN = 0,
|
NM_STATE_UNKNOWN = 0,
|
||||||
NM_STATE_ASLEEP = 10,
|
NM_STATE_ASLEEP = 10,
|
||||||
|
NM_STATE_DISABLED = 10,
|
||||||
NM_STATE_DISCONNECTED = 20,
|
NM_STATE_DISCONNECTED = 20,
|
||||||
NM_STATE_DISCONNECTING = 30,
|
NM_STATE_DISCONNECTING = 30,
|
||||||
NM_STATE_CONNECTING = 40,
|
NM_STATE_CONNECTING = 40,
|
||||||
@@ -122,6 +124,12 @@ void LinuxNetworkWatcherWorker::initialize() {
|
|||||||
SLOT(propertyChanged(QString, QVariantMap, QStringList)));
|
SLOT(propertyChanged(QString, QVariantMap, QStringList)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QVariant currentState = nm.property("State");
|
||||||
|
if (currentState.isValid()) {
|
||||||
|
m_previousNMState = currentState.toUInt();
|
||||||
|
logger.debug() << "Initial NM state:" << m_previousNMState;
|
||||||
|
}
|
||||||
|
|
||||||
QDBusConnection::systemBus().connect(DBUS_NETWORKMANAGER,
|
QDBusConnection::systemBus().connect(DBUS_NETWORKMANAGER,
|
||||||
DBUS_NETWORKMANAGER_PATH,
|
DBUS_NETWORKMANAGER_PATH,
|
||||||
DBUS_NETWORKMANAGER,
|
DBUS_NETWORKMANAGER,
|
||||||
@@ -199,10 +207,13 @@ void LinuxNetworkWatcherWorker::checkDevices() {
|
|||||||
|
|
||||||
void LinuxNetworkWatcherWorker::NMStateChanged(quint32 state)
|
void LinuxNetworkWatcherWorker::NMStateChanged(quint32 state)
|
||||||
{
|
{
|
||||||
if (state == NM_STATE_ASLEEP) {
|
logger.debug() << "NMStateChanged " << state;
|
||||||
emit wakeup();
|
|
||||||
}
|
|
||||||
|
|
||||||
logger.debug() << "NMStateChanged " << state;
|
if (state == NM_STATE_ASLEEP || state == NM_STATE_DISABLED) {
|
||||||
}
|
emit wakeup();
|
||||||
|
} else if (state >= NM_STATE_CONNECTED_SITE && m_previousNMState < NM_STATE_CONNECTED_SITE) {
|
||||||
|
emit networkChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
m_previousNMState = state;
|
||||||
|
}
|
||||||
@@ -24,6 +24,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 wakeup();
|
void wakeup();
|
||||||
|
void networkChanged();
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void initialize();
|
void initialize();
|
||||||
@@ -34,10 +35,12 @@ class LinuxNetworkWatcherWorker final : public QObject {
|
|||||||
void NMStateChanged(quint32 state);
|
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
|
||||||
// initialization. When a property of them changes, we check if the access
|
// initialization. When a property of them changes, we check if the access
|
||||||
// point is active and unsecure.
|
// point is active and unsecure.
|
||||||
QStringList m_devicePaths;
|
QStringList m_devicePaths;
|
||||||
|
quint32 m_previousNMState = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // LINUXNETWORKWATCHERWORKER_H
|
#endif // LINUXNETWORKWATCHERWORKER_H
|
||||||
|
|||||||
+46
-26
@@ -57,11 +57,15 @@ void VpnConnection::onKillSwitchModeChanged(bool enabled)
|
|||||||
{
|
{
|
||||||
#ifdef AMNEZIA_DESKTOP
|
#ifdef AMNEZIA_DESKTOP
|
||||||
IpcClient::withInterface([enabled](QSharedPointer<IpcInterfaceReplica> iface){
|
IpcClient::withInterface([enabled](QSharedPointer<IpcInterfaceReplica> iface){
|
||||||
QRemoteObjectPendingReply<bool> reply = iface->refreshKillSwitch(enabled);
|
auto reply = iface->refreshKillSwitch(enabled);
|
||||||
if (reply.waitForFinished() && reply.returnValue())
|
auto *watcher = new QRemoteObjectPendingCallWatcher(reply);
|
||||||
qDebug() << "VpnConnection::onKillSwitchModeChanged: Killswitch refreshed";
|
QObject::connect(watcher, &QRemoteObjectPendingCallWatcher::finished, [watcher]() {
|
||||||
else
|
if (watcher->returnValue().toBool())
|
||||||
qWarning() << "VpnConnection::onKillSwitchModeChanged: Failed to execute remote refreshKillSwitch call";
|
qDebug() << "VpnConnection::onKillSwitchModeChanged: Killswitch refreshed";
|
||||||
|
else
|
||||||
|
qWarning() << "VpnConnection::onKillSwitchModeChanged: Failed to refresh killswitch";
|
||||||
|
watcher->deleteLater();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@@ -76,15 +80,19 @@ void VpnConnection::onConnectionStateChanged(Vpn::ConnectionState state)
|
|||||||
case Vpn::ConnectionState::Connected: {
|
case Vpn::ConnectionState::Connected: {
|
||||||
iface->resetIpStack();
|
iface->resetIpStack();
|
||||||
|
|
||||||
auto flushDns = iface->flushDns();
|
|
||||||
if (flushDns.waitForFinished() && flushDns.returnValue())
|
|
||||||
qDebug() << "VpnConnection::onConnectionStateChanged: Successfully flushed DNS";
|
|
||||||
else
|
|
||||||
qWarning() << "VpnConnection::onConnectionStateChanged: Failed to clear saved routes";
|
|
||||||
|
|
||||||
|
|
||||||
if (!ContainerProps::isAwgContainer(container) &&
|
if (!ContainerProps::isAwgContainer(container) &&
|
||||||
container != DockerContainer::WireGuard) {
|
container != DockerContainer::WireGuard) {
|
||||||
|
auto flushDnsReply = iface->flushDns();
|
||||||
|
auto *flushDnsWatcher = new QRemoteObjectPendingCallWatcher(flushDnsReply, this);
|
||||||
|
QObject::connect(flushDnsWatcher, &QRemoteObjectPendingCallWatcher::finished, this,
|
||||||
|
[flushDnsWatcher]() {
|
||||||
|
if (flushDnsWatcher->returnValue().toBool())
|
||||||
|
qDebug() << "VpnConnection::onConnectionStateChanged: Successfully flushed DNS";
|
||||||
|
else
|
||||||
|
qWarning() << "VpnConnection::onConnectionStateChanged: Failed to flush DNS";
|
||||||
|
flushDnsWatcher->deleteLater();
|
||||||
|
});
|
||||||
|
|
||||||
QString dns1 = m_vpnConfiguration.value(config_key::dns1).toString();
|
QString dns1 = m_vpnConfiguration.value(config_key::dns1).toString();
|
||||||
QString dns2 = m_vpnConfiguration.value(config_key::dns2).toString();
|
QString dns2 = m_vpnConfiguration.value(config_key::dns2).toString();
|
||||||
|
|
||||||
@@ -109,17 +117,25 @@ void VpnConnection::onConnectionStateChanged(Vpn::ConnectionState state)
|
|||||||
} break;
|
} break;
|
||||||
case Vpn::ConnectionState::Disconnected:
|
case Vpn::ConnectionState::Disconnected:
|
||||||
case Vpn::ConnectionState::Error: {
|
case Vpn::ConnectionState::Error: {
|
||||||
auto flushDns = iface->flushDns();
|
auto flushDnsReply = iface->flushDns();
|
||||||
if (flushDns.waitForFinished() && flushDns.returnValue())
|
auto *flushDnsWatcher = new QRemoteObjectPendingCallWatcher(flushDnsReply);
|
||||||
qDebug() << "VpnConnection::onConnectionStateChanged: Successfully flushed DNS";
|
QObject::connect(flushDnsWatcher, &QRemoteObjectPendingCallWatcher::finished, [flushDnsWatcher]() {
|
||||||
else
|
if (flushDnsWatcher->returnValue().toBool())
|
||||||
qWarning() << "VpnConnection::onConnectionStateChanged: Failed to flush DNS";
|
qDebug() << "VpnConnection::onConnectionStateChanged: Successfully flushed DNS";
|
||||||
|
else
|
||||||
|
qWarning() << "VpnConnection::onConnectionStateChanged: Failed to flush DNS";
|
||||||
|
flushDnsWatcher->deleteLater();
|
||||||
|
});
|
||||||
|
|
||||||
auto clearSavedRoutes = iface->clearSavedRoutes();
|
auto clearSavedRoutesReply = iface->clearSavedRoutes();
|
||||||
if (clearSavedRoutes.waitForFinished() && clearSavedRoutes.returnValue())
|
auto *clearRoutesWatcher = new QRemoteObjectPendingCallWatcher(clearSavedRoutesReply);
|
||||||
qDebug() << "VpnConnection::onConnectionStateChanged: Successfully cleared saved routes";
|
QObject::connect(clearRoutesWatcher, &QRemoteObjectPendingCallWatcher::finished, [clearRoutesWatcher]() {
|
||||||
else
|
if (clearRoutesWatcher->returnValue().toBool())
|
||||||
qWarning() << "VpnConnection::onConnectionStateChanged: Failed to clear saved routes";
|
qDebug() << "VpnConnection::onConnectionStateChanged: Successfully cleared saved routes";
|
||||||
|
else
|
||||||
|
qWarning() << "VpnConnection::onConnectionStateChanged: Failed to clear saved routes";
|
||||||
|
clearRoutesWatcher->deleteLater();
|
||||||
|
});
|
||||||
} break;
|
} break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@@ -182,8 +198,12 @@ void VpnConnection::addSitesRoutes(const QString &gw, Settings::RouteMode mode)
|
|||||||
}
|
}
|
||||||
IpcClient::withInterface([](QSharedPointer<IpcInterfaceReplica> iface) {
|
IpcClient::withInterface([](QSharedPointer<IpcInterfaceReplica> iface) {
|
||||||
auto reply = iface->flushDns();
|
auto reply = iface->flushDns();
|
||||||
if (reply.waitForFinished() || !reply.returnValue())
|
auto *w = new QRemoteObjectPendingCallWatcher(reply);
|
||||||
qWarning() << "VpnConnection::addSitesRoutes: Failed to flush DNS";
|
QObject::connect(w, &QRemoteObjectPendingCallWatcher::finished, [w]() {
|
||||||
|
if (!w->returnValue().toBool())
|
||||||
|
qWarning() << "VpnConnection::addSitesRoutes: Failed to flush DNS";
|
||||||
|
w->deleteLater();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -219,8 +239,8 @@ ErrorCode VpnConnection::lastError() const
|
|||||||
return m_vpnProtocol.data()->lastError();
|
return m_vpnProtocol.data()->lastError();
|
||||||
}
|
}
|
||||||
|
|
||||||
void VpnConnection::connectToVpn(int serverIndex, const ServerCredentials &credentials, DockerContainer container,
|
void VpnConnection::connectToVpn(int serverIndex, const amnezia::ServerCredentials &credentials,
|
||||||
const QJsonObject &vpnConfiguration)
|
amnezia::DockerContainer container, const QJsonObject &vpnConfiguration)
|
||||||
{
|
{
|
||||||
qDebug() << QString("Trying to connect to VPN, server index is %1, container is %2, route mode is")
|
qDebug() << QString("Trying to connect to VPN, server index is %1, container is %2, route mode is")
|
||||||
.arg(serverIndex)
|
.arg(serverIndex)
|
||||||
|
|||||||
@@ -44,7 +44,8 @@ public:
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void connectToVpn(int serverIndex, const ServerCredentials &credentials, DockerContainer container, const QJsonObject &vpnConfiguration);
|
void connectToVpn(int serverIndex, const amnezia::ServerCredentials &credentials,
|
||||||
|
amnezia::DockerContainer container, const QJsonObject &vpnConfiguration);
|
||||||
void reconnectToVpn();
|
void reconnectToVpn();
|
||||||
void disconnectFromVpn();
|
void disconnectFromVpn();
|
||||||
|
|
||||||
|
|||||||
@@ -53,7 +53,9 @@ bool KillSwitch::refresh(bool enabled)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(Q_OS_LINUX) || defined(Q_OS_MACOS)
|
#if defined(Q_OS_LINUX) || defined(Q_OS_MACOS)
|
||||||
m_appSettigns->setValue("Conf/strictKillSwitchEnabled", enabled);
|
if (!m_appSettigns.isNull()) {
|
||||||
|
m_appSettigns->setValue("Conf/strictKillSwitchEnabled", enabled);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (isStrictKillSwitchEnabled()) {
|
if (isStrictKillSwitchEnabled()) {
|
||||||
@@ -70,6 +72,11 @@ bool KillSwitch::isStrictKillSwitchEnabled()
|
|||||||
QSettings RegHLM("HKEY_LOCAL_MACHINE\\Software\\" + QString(ORGANIZATION_NAME)
|
QSettings RegHLM("HKEY_LOCAL_MACHINE\\Software\\" + QString(ORGANIZATION_NAME)
|
||||||
+ "\\" + QString(APPLICATION_NAME), QSettings::NativeFormat);
|
+ "\\" + QString(APPLICATION_NAME), QSettings::NativeFormat);
|
||||||
return RegHLM.value("strictKillSwitchEnabled", false).toBool();
|
return RegHLM.value("strictKillSwitchEnabled", false).toBool();
|
||||||
|
#endif
|
||||||
|
#if defined(Q_OS_LINUX) || defined(Q_OS_MACOS)
|
||||||
|
if (m_appSettigns.isNull()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
return m_appSettigns->value("Conf/strictKillSwitchEnabled", false).toBool();
|
return m_appSettigns->value("Conf/strictKillSwitchEnabled", false).toBool();
|
||||||
}
|
}
|
||||||
@@ -86,7 +93,7 @@ bool KillSwitch::disableKillSwitch() {
|
|||||||
LinuxFirewall::setAnchorEnabled(LinuxFirewall::Both, QStringLiteral("290.allowDHCP"), false);
|
LinuxFirewall::setAnchorEnabled(LinuxFirewall::Both, QStringLiteral("290.allowDHCP"), false);
|
||||||
LinuxFirewall::setAnchorEnabled(LinuxFirewall::Both, QStringLiteral("300.allowLAN"), false);
|
LinuxFirewall::setAnchorEnabled(LinuxFirewall::Both, QStringLiteral("300.allowLAN"), false);
|
||||||
LinuxFirewall::setAnchorEnabled(LinuxFirewall::IPv4, QStringLiteral("310.blockDNS"), false);
|
LinuxFirewall::setAnchorEnabled(LinuxFirewall::IPv4, QStringLiteral("310.blockDNS"), false);
|
||||||
LinuxFirewall::setAnchorEnabled(LinuxFirewall::IPv4, QStringLiteral("320.allowDNS"), false);
|
LinuxFirewall::setAnchorEnabled(LinuxFirewall::Both, QStringLiteral("320.allowDNS"), false);
|
||||||
LinuxFirewall::setAnchorEnabled(LinuxFirewall::Both, QStringLiteral("400.allowPIA"), false);
|
LinuxFirewall::setAnchorEnabled(LinuxFirewall::Both, QStringLiteral("400.allowPIA"), false);
|
||||||
} else {
|
} else {
|
||||||
LinuxFirewall::setAnchorEnabled(LinuxFirewall::Both, QStringLiteral("000.allowLoopback"), true);
|
LinuxFirewall::setAnchorEnabled(LinuxFirewall::Both, QStringLiteral("000.allowLoopback"), true);
|
||||||
@@ -98,7 +105,7 @@ bool KillSwitch::disableKillSwitch() {
|
|||||||
LinuxFirewall::setAnchorEnabled(LinuxFirewall::Both, QStringLiteral("290.allowDHCP"), true);
|
LinuxFirewall::setAnchorEnabled(LinuxFirewall::Both, QStringLiteral("290.allowDHCP"), true);
|
||||||
LinuxFirewall::setAnchorEnabled(LinuxFirewall::Both, QStringLiteral("300.allowLAN"), true);
|
LinuxFirewall::setAnchorEnabled(LinuxFirewall::Both, QStringLiteral("300.allowLAN"), true);
|
||||||
LinuxFirewall::setAnchorEnabled(LinuxFirewall::IPv4, QStringLiteral("310.blockDNS"), false);
|
LinuxFirewall::setAnchorEnabled(LinuxFirewall::IPv4, QStringLiteral("310.blockDNS"), false);
|
||||||
LinuxFirewall::setAnchorEnabled(LinuxFirewall::IPv4, QStringLiteral("320.allowDNS"), true);
|
LinuxFirewall::setAnchorEnabled(LinuxFirewall::Both, QStringLiteral("320.allowDNS"), true);
|
||||||
LinuxFirewall::setAnchorEnabled(LinuxFirewall::Both, QStringLiteral("400.allowPIA"), false);
|
LinuxFirewall::setAnchorEnabled(LinuxFirewall::Both, QStringLiteral("400.allowPIA"), false);
|
||||||
LinuxFirewall::uninstall();
|
LinuxFirewall::uninstall();
|
||||||
}
|
}
|
||||||
@@ -335,7 +342,7 @@ bool KillSwitch::enableKillSwitch(const QJsonObject &configStr, int vpnAdapterIn
|
|||||||
}
|
}
|
||||||
|
|
||||||
LinuxFirewall::updateDNSServers(dnsServers);
|
LinuxFirewall::updateDNSServers(dnsServers);
|
||||||
LinuxFirewall::setAnchorEnabled(LinuxFirewall::IPv4, QStringLiteral("320.allowDNS"), true);
|
LinuxFirewall::setAnchorEnabled(LinuxFirewall::Both, QStringLiteral("320.allowDNS"), true);
|
||||||
LinuxFirewall::setAnchorEnabled(LinuxFirewall::Both, QStringLiteral("400.allowPIA"), true);
|
LinuxFirewall::setAnchorEnabled(LinuxFirewall::Both, QStringLiteral("400.allowPIA"), true);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ public:
|
|||||||
bool isStrictKillSwitchEnabled();
|
bool isStrictKillSwitchEnabled();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
KillSwitch(QObject* parent) {};
|
explicit KillSwitch(QObject* parent) : QObject(parent) {}
|
||||||
QStringList m_allowedRanges;
|
QStringList m_allowedRanges;
|
||||||
QSharedPointer<SecureQSettings> m_appSettigns;
|
QSharedPointer<SecureQSettings> m_appSettigns;
|
||||||
|
|
||||||
|
|||||||
@@ -120,18 +120,20 @@ bool RouterLinux::routeDelete(const QString &ipWithSubnet, const QString &gw, co
|
|||||||
((struct sockaddr_in *)&route.rt_gateway)->sin_family = AF_INET;
|
((struct sockaddr_in *)&route.rt_gateway)->sin_family = AF_INET;
|
||||||
((struct sockaddr_in *)&route.rt_gateway)->sin_addr.s_addr = inet_addr(gw.toStdString().c_str());
|
((struct sockaddr_in *)&route.rt_gateway)->sin_addr.s_addr = inet_addr(gw.toStdString().c_str());
|
||||||
((struct sockaddr_in *)&route.rt_gateway)->sin_port = 0;
|
((struct sockaddr_in *)&route.rt_gateway)->sin_port = 0;
|
||||||
|
|
||||||
// set host rejecting
|
// set host rejecting
|
||||||
((struct sockaddr_in *)&route.rt_dst)->sin_family = AF_INET;
|
((struct sockaddr_in *)&route.rt_dst)->sin_family = AF_INET;
|
||||||
((struct sockaddr_in *)&route.rt_dst)->sin_addr.s_addr = inet_addr(ip.toStdString().c_str());
|
((struct sockaddr_in *)&route.rt_dst)->sin_addr.s_addr = inet_addr(ip.toStdString().c_str());
|
||||||
((struct sockaddr_in *)&route.rt_dst)->sin_port = 0;
|
((struct sockaddr_in *)&route.rt_dst)->sin_port = 0;
|
||||||
|
|
||||||
// set mask
|
// set mask
|
||||||
((struct sockaddr_in *)&route.rt_genmask)->sin_family = AF_INET;
|
((struct sockaddr_in *)&route.rt_genmask)->sin_family = AF_INET;
|
||||||
((struct sockaddr_in *)&route.rt_genmask)->sin_addr.s_addr = inet_addr(mask.toStdString().c_str());
|
((struct sockaddr_in *)&route.rt_genmask)->sin_addr.s_addr = inet_addr(mask.toStdString().c_str());
|
||||||
((struct sockaddr_in *)&route.rt_genmask)->sin_port = 0;
|
((struct sockaddr_in *)&route.rt_genmask)->sin_port = 0;
|
||||||
|
|
||||||
route.rt_flags = RTF_UP | RTF_GATEWAY;
|
route.rt_flags = RTF_UP | RTF_GATEWAY;
|
||||||
route.rt_metric = 0;
|
|
||||||
//route.rt_dev = "ens33";
|
//route.rt_dev = "ens33";
|
||||||
|
route.rt_metric = 0;
|
||||||
|
|
||||||
if (ioctl(sock, SIOCDELRT, &route) < 0)
|
if (ioctl(sock, SIOCDELRT, &route) < 0)
|
||||||
{
|
{
|
||||||
@@ -155,36 +157,29 @@ bool RouterLinux::routeDeleteList(const QString &gw, const QStringList &ips)
|
|||||||
bool RouterLinux::isServiceActive(const QString &serviceName) {
|
bool RouterLinux::isServiceActive(const QString &serviceName) {
|
||||||
QProcess process;
|
QProcess process;
|
||||||
process.start("systemctl", { "is-active", "--quiet", serviceName });
|
process.start("systemctl", { "is-active", "--quiet", serviceName });
|
||||||
process.waitForFinished();
|
if (!process.waitForFinished(2000)) {
|
||||||
|
process.kill();
|
||||||
|
process.waitForFinished(500);
|
||||||
|
}
|
||||||
return process.exitCode() == 0;
|
return process.exitCode() == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RouterLinux::flushDns()
|
bool RouterLinux::flushDns()
|
||||||
{
|
{
|
||||||
QProcess p;
|
|
||||||
p.setProcessChannelMode(QProcess::MergedChannels);
|
|
||||||
|
|
||||||
//check what the dns manager use
|
//check what the dns manager use
|
||||||
if (isServiceActive("nscd.service")) {
|
if (isServiceActive("nscd.service")) {
|
||||||
qDebug() << "Restarting nscd.service";
|
qDebug() << "Flushing nscd cache";
|
||||||
p.start("systemctl", { "restart", "nscd" });
|
QProcess::startDetached("nscd", { "--invalidate=hosts" });
|
||||||
|
return true;
|
||||||
} else if (isServiceActive("systemd-resolved.service")) {
|
} else if (isServiceActive("systemd-resolved.service")) {
|
||||||
qDebug() << "Restarting systemd-resolved.service";
|
qDebug() << "Flushing systemd-resolved cache";
|
||||||
p.start("systemctl", { "restart", "systemd-resolved" });
|
QProcess::startDetached("resolvectl", { "flush-caches" });
|
||||||
|
qDebug().noquote() << "Flush dns requested (non-blocking)";
|
||||||
|
return true;
|
||||||
} else {
|
} else {
|
||||||
qDebug() << "No suitable DNS manager found.";
|
qDebug() << "No suitable DNS manager found.";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
p.waitForFinished();
|
|
||||||
QByteArray output(p.readAll());
|
|
||||||
if (output.isEmpty())
|
|
||||||
qDebug().noquote() << "Flush dns completed";
|
|
||||||
else
|
|
||||||
qDebug().noquote() << "OUTPUT systemctl restart nscd/systemd-resolved: " + output;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RouterLinux::createTun(const QString &dev, const QString &subnet) {
|
bool RouterLinux::createTun(const QString &dev, const QString &subnet) {
|
||||||
|
|||||||
Reference in New Issue
Block a user