mirror of
https://github.com/amnezia-vpn/amnezia-client.git
synced 2026-06-24 02:00:24 +07:00
fix: Linux dns without dbus
This commit is contained in:
@@ -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)) {
|
||||||
@@ -605,6 +601,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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,21 +4,14 @@
|
|||||||
|
|
||||||
#include "dnsutilslinux.h"
|
#include "dnsutilslinux.h"
|
||||||
|
|
||||||
#include <net/if.h>
|
#include <QDir>
|
||||||
|
#include <QFile>
|
||||||
#include <QDBusVariant>
|
#include <QFileInfo>
|
||||||
#include <QTimer>
|
#include <QProcess>
|
||||||
#include <QtDBus/QtDBus>
|
|
||||||
|
|
||||||
#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");
|
||||||
}
|
}
|
||||||
@@ -26,197 +19,126 @@ 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;
|
||||||
|
} else {
|
||||||
|
m_resolvConfOriginal = QStringLiteral("__file__");
|
||||||
|
logger.debug()
|
||||||
|
<< "resolv.conf is a regular file; will restore stub on disconnect";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!m_stateFilePath.isEmpty()) {
|
||||||
|
QFile sf(m_stateFilePath);
|
||||||
|
if (sf.open(QIODevice::WriteOnly | QIODevice::Text))
|
||||||
|
sf.write(m_resolvConfOriginal.toUtf8());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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";
|
||||||
|
static const char* kStub = "/run/systemd/resolve/stub-resolv.conf";
|
||||||
|
|
||||||
|
QFile::remove(kPath);
|
||||||
|
|
||||||
|
const QString target = (original == QStringLiteral("__file__"))
|
||||||
|
? QLatin1String(kStub)
|
||||||
|
: original;
|
||||||
|
|
||||||
|
QFile::link(target, kPath);
|
||||||
|
logger.debug() << "Restored resolv.conf symlink to" << target;
|
||||||
|
}
|
||||||
|
|
||||||
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;
|
writeResolvConf(resolvers);
|
||||||
return false;
|
|
||||||
}
|
QProcess::startDetached("resolvectl", {"flush-caches"});
|
||||||
|
|
||||||
setLinkDNS(m_ifindex, resolvers);
|
|
||||||
setLinkDefaultRoute(m_ifindex, true);
|
|
||||||
setLinkDomains(m_ifindex, {DnsLinkDomain(".", true)});
|
|
||||||
updateLinkDomains();
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DnsUtilsLinux::restoreResolvers() {
|
bool DnsUtilsLinux::restoreResolvers() {
|
||||||
for (auto iterator = m_linkDomains.constBegin();
|
logger.debug() << "restoreResolvers: original="
|
||||||
iterator != m_linkDomains.constEnd(); ++iterator) {
|
<< (m_resolvConfOriginal.isEmpty() ? "(empty)"
|
||||||
setLinkDomains(iterator.key(), iterator.value());
|
: m_resolvConfOriginal);
|
||||||
|
|
||||||
|
if (m_resolvConfOriginal.isEmpty()) {
|
||||||
|
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 | QIODevice::Text)) {
|
||||||
|
m_resolvConfOriginal = QString::fromUtf8(sf.readAll()).trimmed();
|
||||||
|
m_stateFilePath = path;
|
||||||
|
sf.close();
|
||||||
|
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) {
|
||||||
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.debug() << "DBus call failed (may be transient after systemd-resolved restart)";
|
|
||||||
}
|
|
||||||
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;
|
|
||||||
call->deleteLater();
|
|
||||||
if (reply.isError()) {
|
|
||||||
// systemd-resolved may still be starting up after a restart — retry a few times
|
|
||||||
if (m_domainRetries++ < 5) {
|
|
||||||
logger.debug() << "systemd-resolved not ready yet, retrying DNS setup ("
|
|
||||||
<< m_domainRetries << "/5)";
|
|
||||||
QTimer::singleShot(500, this, &DnsUtilsLinux::updateLinkDomains);
|
|
||||||
} else {
|
|
||||||
logger.warning() << "Failed to configure DNS after 5 retries";
|
|
||||||
m_domainRetries = 0;
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
m_domainRetries = 0;
|
|
||||||
|
|
||||||
/* 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
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,20 +23,12 @@ 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;
|
QString m_resolvConfOriginal;
|
||||||
int m_domainRetries = 0;
|
QString m_stateFilePath;
|
||||||
QMap<int, DnsLinkDomainList> m_linkDomains;
|
|
||||||
QDBusInterface* m_resolver = nullptr;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // DNSUTILSLINUX_H
|
#endif // DNSUTILSLINUX_H
|
||||||
|
|||||||
+37
-17
@@ -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);
|
||||||
|
QObject::connect(watcher, &QRemoteObjectPendingCallWatcher::finished, [watcher]() {
|
||||||
|
if (watcher->returnValue().toBool())
|
||||||
qDebug() << "VpnConnection::onKillSwitchModeChanged: Killswitch refreshed";
|
qDebug() << "VpnConnection::onKillSwitchModeChanged: Killswitch refreshed";
|
||||||
else
|
else
|
||||||
qWarning() << "VpnConnection::onKillSwitchModeChanged: Failed to execute remote refreshKillSwitch call";
|
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);
|
||||||
|
QObject::connect(flushDnsWatcher, &QRemoteObjectPendingCallWatcher::finished, [flushDnsWatcher]() {
|
||||||
|
if (flushDnsWatcher->returnValue().toBool())
|
||||||
qDebug() << "VpnConnection::onConnectionStateChanged: Successfully flushed DNS";
|
qDebug() << "VpnConnection::onConnectionStateChanged: Successfully flushed DNS";
|
||||||
else
|
else
|
||||||
qWarning() << "VpnConnection::onConnectionStateChanged: Failed to flush DNS";
|
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);
|
||||||
|
QObject::connect(clearRoutesWatcher, &QRemoteObjectPendingCallWatcher::finished, [clearRoutesWatcher]() {
|
||||||
|
if (clearRoutesWatcher->returnValue().toBool())
|
||||||
qDebug() << "VpnConnection::onConnectionStateChanged: Successfully cleared saved routes";
|
qDebug() << "VpnConnection::onConnectionStateChanged: Successfully cleared saved routes";
|
||||||
else
|
else
|
||||||
qWarning() << "VpnConnection::onConnectionStateChanged: Failed to clear saved routes";
|
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);
|
||||||
|
QObject::connect(w, &QRemoteObjectPendingCallWatcher::finished, [w]() {
|
||||||
|
if (!w->returnValue().toBool())
|
||||||
qWarning() << "VpnConnection::addSitesRoutes: Failed to flush DNS";
|
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)
|
||||||
|
if (!m_appSettigns.isNull()) {
|
||||||
m_appSettigns->setValue("Conf/strictKillSwitchEnabled", enabled);
|
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;
|
||||||
|
|
||||||
|
|||||||
@@ -155,36 +155,40 @@ 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() << "Restarting nscd.service";
|
||||||
|
QProcess p;
|
||||||
|
p.setProcessChannelMode(QProcess::MergedChannels);
|
||||||
p.start("systemctl", { "restart", "nscd" });
|
p.start("systemctl", { "restart", "nscd" });
|
||||||
|
if (!p.waitForFinished(3000)) {
|
||||||
|
qDebug() << "nscd restart timed out, killing process";
|
||||||
|
p.kill();
|
||||||
|
p.waitForFinished(500);
|
||||||
|
}
|
||||||
|
QByteArray output(p.readAll());
|
||||||
|
if (!output.isEmpty())
|
||||||
|
qDebug().noquote() << "OUTPUT systemctl restart nscd: " + output;
|
||||||
|
qDebug().noquote() << "Flush dns completed";
|
||||||
|
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