mirror of
https://github.com/amnezia-vpn/amnezia-client.git
synced 2026-05-08 14:33:23 +00:00
fix: Linux dns without dbus
This commit is contained in:
@@ -142,10 +142,6 @@ bool Daemon::activate(const InterfaceConfig& config) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!maybeUpdateResolvers(config)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// set routing
|
||||
for (const IPAddress& ip : config.m_allowedIPAddressRanges) {
|
||||
if (!wgutils()->updateRoutePrefix(ip)) {
|
||||
@@ -605,6 +601,7 @@ void Daemon::checkHandshake() {
|
||||
}
|
||||
if (status.m_handshake != 0) {
|
||||
connection.m_date.setMSecsSinceEpoch(status.m_handshake);
|
||||
maybeUpdateResolvers(config);
|
||||
emit connected(status.m_pubkey);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,21 +4,14 @@
|
||||
|
||||
#include "dnsutilslinux.h"
|
||||
|
||||
#include <net/if.h>
|
||||
|
||||
#include <QDBusVariant>
|
||||
#include <QTimer>
|
||||
#include <QtDBus/QtDBus>
|
||||
#include <QDir>
|
||||
#include <QFile>
|
||||
#include <QFileInfo>
|
||||
#include <QProcess>
|
||||
|
||||
#include "leakdetector.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 {
|
||||
Logger logger("DnsUtilsLinux");
|
||||
}
|
||||
@@ -26,197 +19,126 @@ Logger logger("DnsUtilsLinux");
|
||||
DnsUtilsLinux::DnsUtilsLinux(QObject* parent) : DnsUtils(parent) {
|
||||
MZ_COUNT_CTOR(DnsUtilsLinux);
|
||||
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() {
|
||||
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.";
|
||||
}
|
||||
|
||||
|
||||
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,
|
||||
const QList<QHostAddress>& resolvers) {
|
||||
m_ifindex = if_nametoindex(qPrintable(ifname));
|
||||
if (m_ifindex <= 0) {
|
||||
logger.error() << "Unable to resolve ifindex for" << ifname;
|
||||
return false;
|
||||
}
|
||||
m_stateFilePath = QStringLiteral("/run/amnezia-dns-%1").arg(ifname);
|
||||
|
||||
writeResolvConf(resolvers);
|
||||
|
||||
QProcess::startDetached("resolvectl", {"flush-caches"});
|
||||
|
||||
setLinkDNS(m_ifindex, resolvers);
|
||||
setLinkDefaultRoute(m_ifindex, true);
|
||||
setLinkDomains(m_ifindex, {DnsLinkDomain(".", true)});
|
||||
updateLinkDomains();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DnsUtilsLinux::restoreResolvers() {
|
||||
for (auto iterator = m_linkDomains.constBegin();
|
||||
iterator != m_linkDomains.constEnd(); ++iterator) {
|
||||
setLinkDomains(iterator.key(), iterator.value());
|
||||
logger.debug() << "restoreResolvers: original="
|
||||
<< (m_resolvConfOriginal.isEmpty() ? "(empty)"
|
||||
: 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 */
|
||||
if (m_ifindex > 0) {
|
||||
QList<QVariant> argumentList = {QVariant::fromValue(m_ifindex)};
|
||||
QDBusPendingReply<> reply = m_resolver->asyncCallWithArgumentList(
|
||||
QStringLiteral("RevertLink"), argumentList);
|
||||
const bool hadDnsState = !m_resolvConfOriginal.isEmpty();
|
||||
restoreResolvConf();
|
||||
|
||||
QDBusPendingCallWatcher* watcher = new QDBusPendingCallWatcher(reply, this);
|
||||
QObject::connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), this,
|
||||
SLOT(dnsCallCompleted(QDBusPendingCallWatcher*)));
|
||||
|
||||
m_ifindex = 0;
|
||||
if (hadDnsState) {
|
||||
QProcess::startDetached("systemctl", {"restart", "systemd-resolved"});
|
||||
}
|
||||
|
||||
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
|
||||
#define DNSUTILSLINUX_H
|
||||
|
||||
#include <QDBusInterface>
|
||||
#include <QDBusPendingCallWatcher>
|
||||
#include <QHostAddress>
|
||||
#include <QList>
|
||||
#include <QString>
|
||||
|
||||
#include "daemon/dnsutils.h"
|
||||
#include "dbustypeslinux.h"
|
||||
|
||||
class DnsUtilsLinux final : public DnsUtils {
|
||||
Q_OBJECT
|
||||
@@ -23,20 +23,12 @@ class DnsUtilsLinux final : public DnsUtils {
|
||||
bool restoreResolvers() override;
|
||||
|
||||
private:
|
||||
void setLinkDNS(int ifindex, const QList<QHostAddress>& resolvers);
|
||||
void setLinkDomains(int ifindex, const QList<DnsLinkDomain>& domains);
|
||||
void setLinkDefaultRoute(int ifindex, bool enable);
|
||||
void updateLinkDomains();
|
||||
|
||||
private slots:
|
||||
void dnsCallCompleted(QDBusPendingCallWatcher*);
|
||||
void dnsDomainsReceived(QDBusPendingCallWatcher*);
|
||||
void writeResolvConf(const QList<QHostAddress>& resolvers);
|
||||
void restoreResolvConf();
|
||||
|
||||
private:
|
||||
int m_ifindex = 0;
|
||||
int m_domainRetries = 0;
|
||||
QMap<int, DnsLinkDomainList> m_linkDomains;
|
||||
QDBusInterface* m_resolver = nullptr;
|
||||
QString m_resolvConfOriginal;
|
||||
QString m_stateFilePath;
|
||||
};
|
||||
|
||||
#endif // DNSUTILSLINUX_H
|
||||
|
||||
@@ -57,11 +57,15 @@ void VpnConnection::onKillSwitchModeChanged(bool enabled)
|
||||
{
|
||||
#ifdef AMNEZIA_DESKTOP
|
||||
IpcClient::withInterface([enabled](QSharedPointer<IpcInterfaceReplica> iface){
|
||||
QRemoteObjectPendingReply<bool> reply = iface->refreshKillSwitch(enabled);
|
||||
if (reply.waitForFinished() && reply.returnValue())
|
||||
qDebug() << "VpnConnection::onKillSwitchModeChanged: Killswitch refreshed";
|
||||
else
|
||||
qWarning() << "VpnConnection::onKillSwitchModeChanged: Failed to execute remote refreshKillSwitch call";
|
||||
auto reply = iface->refreshKillSwitch(enabled);
|
||||
auto *watcher = new QRemoteObjectPendingCallWatcher(reply);
|
||||
QObject::connect(watcher, &QRemoteObjectPendingCallWatcher::finished, [watcher]() {
|
||||
if (watcher->returnValue().toBool())
|
||||
qDebug() << "VpnConnection::onKillSwitchModeChanged: Killswitch refreshed";
|
||||
else
|
||||
qWarning() << "VpnConnection::onKillSwitchModeChanged: Failed to refresh killswitch";
|
||||
watcher->deleteLater();
|
||||
});
|
||||
});
|
||||
#endif
|
||||
}
|
||||
@@ -76,15 +80,19 @@ void VpnConnection::onConnectionStateChanged(Vpn::ConnectionState state)
|
||||
case Vpn::ConnectionState::Connected: {
|
||||
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) &&
|
||||
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 dns2 = m_vpnConfiguration.value(config_key::dns2).toString();
|
||||
|
||||
@@ -109,17 +117,25 @@ void VpnConnection::onConnectionStateChanged(Vpn::ConnectionState state)
|
||||
} break;
|
||||
case Vpn::ConnectionState::Disconnected:
|
||||
case Vpn::ConnectionState::Error: {
|
||||
auto flushDns = iface->flushDns();
|
||||
if (flushDns.waitForFinished() && flushDns.returnValue())
|
||||
qDebug() << "VpnConnection::onConnectionStateChanged: Successfully flushed DNS";
|
||||
else
|
||||
qWarning() << "VpnConnection::onConnectionStateChanged: Failed to flush DNS";
|
||||
auto flushDnsReply = iface->flushDns();
|
||||
auto *flushDnsWatcher = new QRemoteObjectPendingCallWatcher(flushDnsReply);
|
||||
QObject::connect(flushDnsWatcher, &QRemoteObjectPendingCallWatcher::finished, [flushDnsWatcher]() {
|
||||
if (flushDnsWatcher->returnValue().toBool())
|
||||
qDebug() << "VpnConnection::onConnectionStateChanged: Successfully flushed DNS";
|
||||
else
|
||||
qWarning() << "VpnConnection::onConnectionStateChanged: Failed to flush DNS";
|
||||
flushDnsWatcher->deleteLater();
|
||||
});
|
||||
|
||||
auto clearSavedRoutes = iface->clearSavedRoutes();
|
||||
if (clearSavedRoutes.waitForFinished() && clearSavedRoutes.returnValue())
|
||||
qDebug() << "VpnConnection::onConnectionStateChanged: Successfully cleared saved routes";
|
||||
else
|
||||
qWarning() << "VpnConnection::onConnectionStateChanged: Failed to clear saved routes";
|
||||
auto clearSavedRoutesReply = iface->clearSavedRoutes();
|
||||
auto *clearRoutesWatcher = new QRemoteObjectPendingCallWatcher(clearSavedRoutesReply);
|
||||
QObject::connect(clearRoutesWatcher, &QRemoteObjectPendingCallWatcher::finished, [clearRoutesWatcher]() {
|
||||
if (clearRoutesWatcher->returnValue().toBool())
|
||||
qDebug() << "VpnConnection::onConnectionStateChanged: Successfully cleared saved routes";
|
||||
else
|
||||
qWarning() << "VpnConnection::onConnectionStateChanged: Failed to clear saved routes";
|
||||
clearRoutesWatcher->deleteLater();
|
||||
});
|
||||
} break;
|
||||
default:
|
||||
break;
|
||||
@@ -182,8 +198,12 @@ void VpnConnection::addSitesRoutes(const QString &gw, Settings::RouteMode mode)
|
||||
}
|
||||
IpcClient::withInterface([](QSharedPointer<IpcInterfaceReplica> iface) {
|
||||
auto reply = iface->flushDns();
|
||||
if (reply.waitForFinished() || !reply.returnValue())
|
||||
qWarning() << "VpnConnection::addSitesRoutes: Failed to flush DNS";
|
||||
auto *w = new QRemoteObjectPendingCallWatcher(reply);
|
||||
QObject::connect(w, &QRemoteObjectPendingCallWatcher::finished, [w]() {
|
||||
if (!w->returnValue().toBool())
|
||||
qWarning() << "VpnConnection::addSitesRoutes: Failed to flush DNS";
|
||||
w->deleteLater();
|
||||
});
|
||||
});
|
||||
break;
|
||||
}
|
||||
@@ -219,8 +239,8 @@ ErrorCode VpnConnection::lastError() const
|
||||
return m_vpnProtocol.data()->lastError();
|
||||
}
|
||||
|
||||
void VpnConnection::connectToVpn(int serverIndex, const ServerCredentials &credentials, DockerContainer container,
|
||||
const QJsonObject &vpnConfiguration)
|
||||
void VpnConnection::connectToVpn(int serverIndex, const amnezia::ServerCredentials &credentials,
|
||||
amnezia::DockerContainer container, const QJsonObject &vpnConfiguration)
|
||||
{
|
||||
qDebug() << QString("Trying to connect to VPN, server index is %1, container is %2, route mode is")
|
||||
.arg(serverIndex)
|
||||
|
||||
@@ -44,7 +44,8 @@ public:
|
||||
#endif
|
||||
|
||||
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 disconnectFromVpn();
|
||||
|
||||
|
||||
@@ -53,7 +53,9 @@ bool KillSwitch::refresh(bool enabled)
|
||||
#endif
|
||||
|
||||
#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
|
||||
|
||||
if (isStrictKillSwitchEnabled()) {
|
||||
@@ -70,6 +72,11 @@ bool KillSwitch::isStrictKillSwitchEnabled()
|
||||
QSettings RegHLM("HKEY_LOCAL_MACHINE\\Software\\" + QString(ORGANIZATION_NAME)
|
||||
+ "\\" + QString(APPLICATION_NAME), QSettings::NativeFormat);
|
||||
return RegHLM.value("strictKillSwitchEnabled", false).toBool();
|
||||
#endif
|
||||
#if defined(Q_OS_LINUX) || defined(Q_OS_MACOS)
|
||||
if (m_appSettigns.isNull()) {
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
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("300.allowLAN"), 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);
|
||||
} else {
|
||||
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("300.allowLAN"), true);
|
||||
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::uninstall();
|
||||
}
|
||||
@@ -335,7 +342,7 @@ bool KillSwitch::enableKillSwitch(const QJsonObject &configStr, int vpnAdapterIn
|
||||
}
|
||||
|
||||
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);
|
||||
#endif
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ public:
|
||||
bool isStrictKillSwitchEnabled();
|
||||
|
||||
private:
|
||||
KillSwitch(QObject* parent) {};
|
||||
explicit KillSwitch(QObject* parent) : QObject(parent) {}
|
||||
QStringList m_allowedRanges;
|
||||
QSharedPointer<SecureQSettings> m_appSettigns;
|
||||
|
||||
|
||||
@@ -155,36 +155,40 @@ bool RouterLinux::routeDeleteList(const QString &gw, const QStringList &ips)
|
||||
bool RouterLinux::isServiceActive(const QString &serviceName) {
|
||||
QProcess process;
|
||||
process.start("systemctl", { "is-active", "--quiet", serviceName });
|
||||
process.waitForFinished();
|
||||
|
||||
if (!process.waitForFinished(2000)) {
|
||||
process.kill();
|
||||
process.waitForFinished(500);
|
||||
}
|
||||
return process.exitCode() == 0;
|
||||
}
|
||||
|
||||
bool RouterLinux::flushDns()
|
||||
{
|
||||
QProcess p;
|
||||
p.setProcessChannelMode(QProcess::MergedChannels);
|
||||
|
||||
//check what the dns manager use
|
||||
if (isServiceActive("nscd.service")) {
|
||||
qDebug() << "Restarting nscd.service";
|
||||
QProcess p;
|
||||
p.setProcessChannelMode(QProcess::MergedChannels);
|
||||
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")) {
|
||||
qDebug() << "Restarting systemd-resolved.service";
|
||||
p.start("systemctl", { "restart", "systemd-resolved" });
|
||||
qDebug() << "Flushing systemd-resolved cache";
|
||||
QProcess::startDetached("resolvectl", { "flush-caches" });
|
||||
qDebug().noquote() << "Flush dns requested (non-blocking)";
|
||||
return true;
|
||||
} else {
|
||||
qDebug() << "No suitable DNS manager found.";
|
||||
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) {
|
||||
|
||||
Reference in New Issue
Block a user