diff --git a/client/platforms/linux/daemon/dnsutilslinux.cpp b/client/platforms/linux/daemon/dnsutilslinux.cpp index 141dcccb2..e5ac459a3 100644 --- a/client/platforms/linux/daemon/dnsutilslinux.cpp +++ b/client/platforms/linux/daemon/dnsutilslinux.cpp @@ -7,9 +7,11 @@ #include #include +#include #include #include +#include "core/networkUtilities.h" #include "leakdetector.h" #include "logger.h" @@ -64,6 +66,15 @@ DnsUtilsLinux::~DnsUtilsLinux() { MZ_COUNT_DTOR(DnsUtilsLinux); if (m_resolver) { + for (auto iterator = m_linkDefaultRoutes.constBegin(); + iterator != m_linkDefaultRoutes.constEnd(); ++iterator) { + QList argumentList; + argumentList << QVariant::fromValue(iterator.key()); + argumentList << QVariant::fromValue(iterator.value()); + m_resolver->asyncCallWithArgumentList(QStringLiteral("SetLinkDefaultRoute"), + argumentList); + } + for (auto iterator = m_linkDomains.constBegin(); iterator != m_linkDomains.constEnd(); ++iterator) { QList argumentList; @@ -82,6 +93,12 @@ DnsUtilsLinux::~DnsUtilsLinux() { bool DnsUtilsLinux::updateResolvers(const QString& ifname, const QList& resolvers) { + for (auto iterator = m_linkDefaultRoutes.constBegin(); + iterator != m_linkDefaultRoutes.constEnd(); ++iterator) { + setLinkDefaultRoute(iterator.key(), iterator.value()); + } + m_linkDefaultRoutes.clear(); + m_ifindex = if_nametoindex(qPrintable(ifname)); if (m_ifindex <= 0) { logger.error() << "Unable to resolve ifindex for" << ifname; @@ -96,9 +113,9 @@ bool DnsUtilsLinux::updateResolvers(const QString& ifname, return true; } + updateLinkDefaultRoutes(); setLinkDNS(m_ifindex, resolvers); setLinkDefaultRoute(m_ifindex, true); - setLinkDomains(m_ifindex, {DnsLinkDomain(".", true)}); updateLinkDomains(); return true; } @@ -107,6 +124,12 @@ bool DnsUtilsLinux::restoreResolvers() { m_pendingIfname.clear(); m_pendingResolvers.clear(); + for (auto iterator = m_linkDefaultRoutes.constBegin(); + iterator != m_linkDefaultRoutes.constEnd(); ++iterator) { + setLinkDefaultRoute(iterator.key(), iterator.value()); + } + m_linkDefaultRoutes.clear(); + for (auto iterator = m_linkDomains.constBegin(); iterator != m_linkDomains.constEnd(); ++iterator) { setLinkDomains(iterator.key(), iterator.value()); @@ -132,7 +155,7 @@ bool DnsUtilsLinux::restoreResolvers() { void DnsUtilsLinux::dnsCallCompleted(QDBusPendingCallWatcher* call) { QDBusPendingReply<> reply = *call; if (reply.isError()) { - logger.debug() << "DBus call failed (may be transient after systemd-resolved restart)"; + logger.error() << "Error received from the DBus service"; } delete call; } @@ -200,6 +223,23 @@ void DnsUtilsLinux::setLinkDefaultRoute(int ifindex, bool enable) { SLOT(dnsCallCompleted(QDBusPendingCallWatcher*))); } +void DnsUtilsLinux::updateLinkDefaultRoutes() { + const QNetworkInterface defaultIface = NetworkUtilities::getGatewayAndIface().second; + const int ifindex = defaultIface.index(); + if (ifindex <= 0) { + logger.warning() << "Unable to determine default route interface"; + return; + } + if ((ifindex == m_ifindex) || m_linkDefaultRoutes.contains(ifindex)) { + return; + } + + // Gateway link normally has DefaultRoute=yes. Keep behavior simple: + // disable it while VPN DNS is active and restore to yes on teardown. + m_linkDefaultRoutes[ifindex] = true; + setLinkDefaultRoute(ifindex, false); +} + void DnsUtilsLinux::updateLinkDomains() { if (!m_resolver) return; /* Get the list of search domains, and remove any others that might conspire diff --git a/client/platforms/linux/daemon/dnsutilslinux.h b/client/platforms/linux/daemon/dnsutilslinux.h index 20ba274f2..f9f03b41e 100644 --- a/client/platforms/linux/daemon/dnsutilslinux.h +++ b/client/platforms/linux/daemon/dnsutilslinux.h @@ -31,6 +31,7 @@ class DnsUtilsLinux final : public DnsUtils { void setLinkDNS(int ifindex, const QList& resolvers); void setLinkDomains(int ifindex, const QList& domains); void setLinkDefaultRoute(int ifindex, bool enable); + void updateLinkDefaultRoutes(); void updateLinkDomains(); private slots: @@ -43,6 +44,7 @@ class DnsUtilsLinux final : public DnsUtils { int m_ifindex = 0; int m_domainRetries = 0; QMap m_linkDomains; + QMap m_linkDefaultRoutes; QScopedPointer m_resolver; QString m_pendingIfname; QList m_pendingResolvers; diff --git a/service/server/router_linux.cpp b/service/server/router_linux.cpp index 44f0e17d4..05becb8dc 100644 --- a/service/server/router_linux.cpp +++ b/service/server/router_linux.cpp @@ -167,22 +167,27 @@ bool RouterLinux::flushDns() //check what the dns manager use if (isServiceActive("nscd.service")) { - qDebug() << "Restarting nscd.service"; - p.start("systemctl", { "restart", "nscd" }); + qDebug() << "Flushing nscd cache"; + p.start("nscd", { "--invalidate=hosts" }); } else if (isServiceActive("systemd-resolved.service")) { - qDebug() << "Restarting systemd-resolved.service"; - p.start("systemctl", { "restart", "systemd-resolved" }); + qDebug() << "Flushing systemd-resolved DNS cache"; + p.start("resolvectl", { "flush-caches" }); } else { qDebug() << "No suitable DNS manager found."; return false; } p.waitForFinished(); - QByteArray output(p.readAll()); + QByteArray output = p.readAll(); + if ((p.exitStatus() != QProcess::NormalExit) || (p.exitCode() != 0)) { + qDebug().noquote() << "Failed to flush DNS: " + output; + return false; + } + if (output.isEmpty()) qDebug().noquote() << "Flush dns completed"; else - qDebug().noquote() << "OUTPUT systemctl restart nscd/systemd-resolved: " + output; + qDebug().noquote() << "OUTPUT dns flush: " + output; return true; }