From a78f42a19969ab19cfc3be2dde87b58081589ac7 Mon Sep 17 00:00:00 2001 From: NickVs2015 Date: Fri, 3 Apr 2026 20:30:08 +0300 Subject: [PATCH 1/7] fix: make dbus async --- .../platforms/linux/daemon/dnsutilslinux.cpp | 96 +++++++++++++++---- client/platforms/linux/daemon/dnsutilslinux.h | 12 ++- 2 files changed, 87 insertions(+), 21 deletions(-) diff --git a/client/platforms/linux/daemon/dnsutilslinux.cpp b/client/platforms/linux/daemon/dnsutilslinux.cpp index cc47202b5..141dcccb2 100644 --- a/client/platforms/linux/daemon/dnsutilslinux.cpp +++ b/client/platforms/linux/daemon/dnsutilslinux.cpp @@ -7,6 +7,7 @@ #include #include +#include #include #include "leakdetector.h" @@ -27,24 +28,53 @@ DnsUtilsLinux::DnsUtilsLinux(QObject* parent) : DnsUtils(parent) { logger.debug() << "DnsUtilsLinux created."; QDBusConnection conn = QDBusConnection::systemBus(); - m_resolver = new QDBusInterface(DBUS_RESOLVE_SERVICE, DBUS_RESOLVE_PATH, - DBUS_RESOLVE_MANAGER, conn, this); + auto* watcher = new QDBusServiceWatcher( + DBUS_RESOLVE_SERVICE, conn, + QDBusServiceWatcher::WatchForRegistration | + QDBusServiceWatcher::WatchForUnregistration, this); + + connect(watcher, &QDBusServiceWatcher::serviceRegistered, + this, &DnsUtilsLinux::onResolverRegistered); + connect(watcher, &QDBusServiceWatcher::serviceUnregistered, + this, &DnsUtilsLinux::onResolverUnregistered); + + if (conn.interface()->isServiceRegistered(DBUS_RESOLVE_SERVICE)) { + onResolverRegistered(); + } +} + +void DnsUtilsLinux::onResolverRegistered() { + m_resolver.reset(new QDBusInterface(DBUS_RESOLVE_SERVICE, DBUS_RESOLVE_PATH, + DBUS_RESOLVE_MANAGER, + QDBusConnection::systemBus())); + logger.debug() << "systemd-resolved available, DNS resolver initialized"; + + if (!m_pendingIfname.isEmpty()) { + logger.debug() << "Re-applying DNS configuration for" << m_pendingIfname; + updateResolvers(m_pendingIfname, m_pendingResolvers); + } +} + +void DnsUtilsLinux::onResolverUnregistered() { + logger.debug() << "systemd-resolved disappeared, dropping DNS resolver"; + m_resolver.reset(); } DnsUtilsLinux::~DnsUtilsLinux() { MZ_COUNT_DTOR(DnsUtilsLinux); - for (auto iterator = m_linkDomains.constBegin(); - iterator != m_linkDomains.constEnd(); ++iterator) { - QList 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); + if (m_resolver) { + for (auto iterator = m_linkDomains.constBegin(); + iterator != m_linkDomains.constEnd(); ++iterator) { + QList 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."; @@ -58,13 +88,25 @@ bool DnsUtilsLinux::updateResolvers(const QString& ifname, return false; } + m_pendingIfname = ifname; + m_pendingResolvers = resolvers; + + if (!m_resolver) { + logger.debug() << "systemd-resolved not ready, queuing DNS configuration"; + return true; + } + setLinkDNS(m_ifindex, resolvers); setLinkDefaultRoute(m_ifindex, true); + setLinkDomains(m_ifindex, {DnsLinkDomain(".", true)}); updateLinkDomains(); return true; } bool DnsUtilsLinux::restoreResolvers() { + m_pendingIfname.clear(); + m_pendingResolvers.clear(); + for (auto iterator = m_linkDomains.constBegin(); iterator != m_linkDomains.constEnd(); ++iterator) { setLinkDomains(iterator.key(), iterator.value()); @@ -72,7 +114,7 @@ bool DnsUtilsLinux::restoreResolvers() { m_linkDomains.clear(); /* Revert the VPN interface's DNS configuration */ - if (m_ifindex > 0) { + if (m_ifindex > 0 && m_resolver) { QList argumentList = {QVariant::fromValue(m_ifindex)}; QDBusPendingReply<> reply = m_resolver->asyncCallWithArgumentList( QStringLiteral("RevertLink"), argumentList); @@ -90,13 +132,14 @@ bool DnsUtilsLinux::restoreResolvers() { void DnsUtilsLinux::dnsCallCompleted(QDBusPendingCallWatcher* call) { QDBusPendingReply<> reply = *call; if (reply.isError()) { - logger.error() << "Error received from the DBus service"; + logger.debug() << "DBus call failed (may be transient after systemd-resolved restart)"; } delete call; } void DnsUtilsLinux::setLinkDNS(int ifindex, const QList& resolvers) { + if (!m_resolver) return; QList resolverList; char ifnamebuf[IF_NAMESIZE]; const char* ifname = if_indextoname(ifindex, ifnamebuf); @@ -121,6 +164,7 @@ void DnsUtilsLinux::setLinkDNS(int ifindex, void DnsUtilsLinux::setLinkDomains(int ifindex, const QList& domains) { + if (!m_resolver) return; char ifnamebuf[IF_NAMESIZE]; const char* ifname = if_indextoname(ifindex, ifnamebuf); if (ifname) { @@ -144,6 +188,7 @@ void DnsUtilsLinux::setLinkDomains(int ifindex, } void DnsUtilsLinux::setLinkDefaultRoute(int ifindex, bool enable) { + if (!m_resolver) return; QList argumentList; argumentList << QVariant::fromValue(ifindex); argumentList << QVariant::fromValue(enable); @@ -156,6 +201,7 @@ void DnsUtilsLinux::setLinkDefaultRoute(int ifindex, bool enable) { } void DnsUtilsLinux::updateLinkDomains() { + if (!m_resolver) return; /* 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. @@ -174,11 +220,20 @@ void DnsUtilsLinux::updateLinkDomains() { void DnsUtilsLinux::dnsDomainsReceived(QDBusPendingCallWatcher* call) { QDBusPendingReply reply = *call; + call->deleteLater(); if (reply.isError()) { - logger.error() << "Error retrieving the DNS domains from the DBus service"; - delete call; + // systemd-resolved may still be starting up after a restart — retry a few times + if (m_ifindex > 0 && 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(); @@ -204,9 +259,10 @@ void DnsUtilsLinux::dnsDomainsReceived(QDBusPendingCallWatcher* call) { } /* Add a root search domain for the new interface. */ - QList newlist = {root}; - setLinkDomains(m_ifindex, newlist); - delete call; + if (m_ifindex > 0) { + QList newlist = {root}; + setLinkDomains(m_ifindex, newlist); + } } static DnsMetatypeRegistrationProxy s_dnsMetatypeProxy; diff --git a/client/platforms/linux/daemon/dnsutilslinux.h b/client/platforms/linux/daemon/dnsutilslinux.h index e4bbd2734..20ba274f2 100644 --- a/client/platforms/linux/daemon/dnsutilslinux.h +++ b/client/platforms/linux/daemon/dnsutilslinux.h @@ -6,7 +6,12 @@ #define DNSUTILSLINUX_H #include +#include #include +#include +#include +#include +#include #include "daemon/dnsutils.h" #include "dbustypeslinux.h" @@ -29,13 +34,18 @@ class DnsUtilsLinux final : public DnsUtils { void updateLinkDomains(); private slots: + void onResolverRegistered(); + void onResolverUnregistered(); void dnsCallCompleted(QDBusPendingCallWatcher*); void dnsDomainsReceived(QDBusPendingCallWatcher*); private: int m_ifindex = 0; + int m_domainRetries = 0; QMap m_linkDomains; - QDBusInterface* m_resolver = nullptr; + QScopedPointer m_resolver; + QString m_pendingIfname; + QList m_pendingResolvers; }; #endif // DNSUTILSLINUX_H From dcb097b0b256a45149c4421eb64d7b5c909b280d Mon Sep 17 00:00:00 2001 From: NickVs2015 Date: Sun, 12 Apr 2026 10:39:59 +0300 Subject: [PATCH 2/7] fix: dns rewrites and flush --- .../platforms/linux/daemon/dnsutilslinux.cpp | 44 ++++++++++++++++++- client/platforms/linux/daemon/dnsutilslinux.h | 2 + service/server/router_linux.cpp | 17 ++++--- 3 files changed, 55 insertions(+), 8 deletions(-) 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; } From 0edffc5f880b5f9d086b02297d8942048fc6afd2 Mon Sep 17 00:00:00 2001 From: NickVs2015 Date: Mon, 13 Apr 2026 21:08:43 +0300 Subject: [PATCH 3/7] fix: NM down/up reconnection problem --- client/core/utils/networkUtilities.cpp | 22 +++++++++++++++------- client/daemon/daemon.cpp | 2 +- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/client/core/utils/networkUtilities.cpp b/client/core/utils/networkUtilities.cpp index 96b9131be..10cd2d689 100644 --- a/client/core/utils/networkUtilities.cpp +++ b/client/core/utils/networkUtilities.cpp @@ -286,7 +286,7 @@ QPair NetworkUtilities::getGatewayAndIface() return { resGateway, QNetworkInterface::interfaceFromIndex(resIndex) }; #endif #ifdef Q_OS_LINUX - constexpr int BUFFER_SIZE = 100; + constexpr int BUFFER_SIZE = 8192; int received_bytes = 0, msg_len = 0, route_attribute_len = 0; int sock = -1, msgseq = 0; struct nlmsghdr *nlh, *nlmsg; @@ -294,7 +294,7 @@ QPair NetworkUtilities::getGatewayAndIface() // 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 msgbuf[100], buffer[BUFFER_SIZE]; char *ptr = buffer; struct timeval tv; @@ -339,8 +339,8 @@ QPair NetworkUtilities::getGatewayAndIface() nlh = (struct nlmsghdr *) ptr; /* Check if the header is valid */ - if((NLMSG_OK(nlmsg, received_bytes) == 0) || - (nlmsg->nlmsg_type == NLMSG_ERROR)) + if((NLMSG_OK(nlh, received_bytes) == 0) || + (nlh->nlmsg_type == NLMSG_ERROR)) { perror("Error in received packet"); return {}; @@ -355,13 +355,15 @@ QPair NetworkUtilities::getGatewayAndIface() } /* Break if its not a multi part message */ - if ((nlmsg->nlmsg_flags & NLM_F_MULTI) == 0) + if ((nlh->nlmsg_flags & NLM_F_MULTI) == 0) break; } - while ((nlmsg->nlmsg_seq != msgseq) || (nlmsg->nlmsg_pid != getpid())); + while ((nlh->nlmsg_seq != msgseq) || (nlh->nlmsg_pid != getpid())); /* parse response */ - for ( ; NLMSG_OK(nlh, received_bytes); nlh = NLMSG_NEXT(nlh, received_bytes)) + int remaining = msg_len + received_bytes; + nlh = (struct nlmsghdr *) buffer; + for ( ; NLMSG_OK(nlh, remaining); nlh = NLMSG_NEXT(nlh, remaining)) { /* Get the route data */ route_entry = (struct rtmsg *) NLMSG_DATA(nlh); @@ -370,6 +372,10 @@ QPair NetworkUtilities::getGatewayAndIface() if (route_entry->rtm_table != RT_TABLE_MAIN) continue; + /* Reset per-route to avoid cross-route state pollution */ + memset(gateway_address, 0, sizeof(gateway_address)); + memset(interface, 0, sizeof(interface)); + route_attribute = (struct rtattr *) RTM_RTA(route_entry); route_attribute_len = RTM_PAYLOAD(nlh); @@ -395,6 +401,8 @@ QPair NetworkUtilities::getGatewayAndIface() break; } } + if (!(*gateway_address) || !(*interface)) + qDebug() << "getGatewayAndIface: no gateway found"; close(sock); return { gateway_address, QNetworkInterface::interfaceFromName(interface) }; #endif diff --git a/client/daemon/daemon.cpp b/client/daemon/daemon.cpp index e74a613f5..4c06cabe9 100644 --- a/client/daemon/daemon.cpp +++ b/client/daemon/daemon.cpp @@ -613,7 +613,7 @@ void Daemon::checkHandshake() { pendingHandshakes++; } } - + // Check again if there were connections that haven't completed a handshake. if (pendingHandshakes > 0) { m_handshakeTimer.start(HANDSHAKE_POLL_MSEC); From c7b7ecd1d69f540e022a39316064824c4a9f4173 Mon Sep 17 00:00:00 2001 From: NickVs2015 Date: Mon, 27 Apr 2026 20:39:27 +0300 Subject: [PATCH 4/7] fix: killswitch compatible --- client/platforms/linux/daemon/dnsutilslinux.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/client/platforms/linux/daemon/dnsutilslinux.cpp b/client/platforms/linux/daemon/dnsutilslinux.cpp index e5ac459a3..83a749d68 100644 --- a/client/platforms/linux/daemon/dnsutilslinux.cpp +++ b/client/platforms/linux/daemon/dnsutilslinux.cpp @@ -302,6 +302,7 @@ void DnsUtilsLinux::dnsDomainsReceived(QDBusPendingCallWatcher* call) { if (m_ifindex > 0) { QList newlist = {root}; setLinkDomains(m_ifindex, newlist); + updateLinkDefaultRoutes(); } } From 970fc2611386140726ccfdaec5078323c454e3c1 Mon Sep 17 00:00:00 2001 From: NickVs2015 Date: Tue, 28 Apr 2026 11:11:16 +0300 Subject: [PATCH 5/7] fix: solve infinite reconnect NM down --- client/platforms/linux/daemon/wireguardutilslinux.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/client/platforms/linux/daemon/wireguardutilslinux.cpp b/client/platforms/linux/daemon/wireguardutilslinux.cpp index 1b7cddc8e..be9ead885 100644 --- a/client/platforms/linux/daemon/wireguardutilslinux.cpp +++ b/client/platforms/linux/daemon/wireguardutilslinux.cpp @@ -237,7 +237,11 @@ bool WireguardUtilsLinux::updatePeer(const InterfaceConfig& config) { // Exclude the server address, except for multihop exit servers. if ((config.m_hopType != InterfaceConfig::MultiHopExit) && (m_rtmonitor != nullptr)) { - m_rtmonitor->addExclusionRoute(IPAddress(config.m_serverIpv4AddrIn)); + if (!config.m_serverIpv4AddrIn.isEmpty() && + !m_rtmonitor->addExclusionRoute(IPAddress(config.m_serverIpv4AddrIn))) { + logger.error() << "No gateway — cannot add server exclusion route"; + return false; + } m_rtmonitor->addExclusionRoute(IPAddress(config.m_serverIpv6AddrIn)); } From fd915a43252e6ba89935a607bb2e0a17c4394671 Mon Sep 17 00:00:00 2001 From: NickVs2015 Date: Wed, 29 Apr 2026 10:18:08 +0300 Subject: [PATCH 6/7] fix: replace m_linkDefaultRoutes map with single m_gatewayIfindex --- .../platforms/linux/daemon/dnsutilslinux.cpp | 62 +++++++------------ client/platforms/linux/daemon/dnsutilslinux.h | 3 +- 2 files changed, 25 insertions(+), 40 deletions(-) diff --git a/client/platforms/linux/daemon/dnsutilslinux.cpp b/client/platforms/linux/daemon/dnsutilslinux.cpp index 83a749d68..e1f9e724e 100644 --- a/client/platforms/linux/daemon/dnsutilslinux.cpp +++ b/client/platforms/linux/daemon/dnsutilslinux.cpp @@ -66,14 +66,8 @@ 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); - } + if (m_gatewayIfindex > 0) + setLinkDefaultRoute(m_gatewayIfindex, true); for (auto iterator = m_linkDomains.constBegin(); iterator != m_linkDomains.constEnd(); ++iterator) { @@ -93,11 +87,10 @@ 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()); + if (m_gatewayIfindex > 0) { + setLinkDefaultRoute(m_gatewayIfindex, true); + m_gatewayIfindex = 0; } - m_linkDefaultRoutes.clear(); m_ifindex = if_nametoindex(qPrintable(ifname)); if (m_ifindex <= 0) { @@ -113,7 +106,12 @@ bool DnsUtilsLinux::updateResolvers(const QString& ifname, return true; } - updateLinkDefaultRoutes(); + const int gwIdx = NetworkUtilities::getGatewayAndIface().second.index(); + if (gwIdx > 0 && gwIdx != m_ifindex && gwIdx != m_gatewayIfindex) { + m_gatewayIfindex = gwIdx; + setLinkDefaultRoute(gwIdx, false); + } + setLinkDNS(m_ifindex, resolvers); setLinkDefaultRoute(m_ifindex, true); updateLinkDomains(); @@ -124,11 +122,10 @@ 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()); + if (m_gatewayIfindex > 0) { + setLinkDefaultRoute(m_gatewayIfindex, true); + m_gatewayIfindex = 0; } - m_linkDefaultRoutes.clear(); for (auto iterator = m_linkDomains.constBegin(); iterator != m_linkDomains.constEnd(); ++iterator) { @@ -155,7 +152,7 @@ bool DnsUtilsLinux::restoreResolvers() { void DnsUtilsLinux::dnsCallCompleted(QDBusPendingCallWatcher* call) { QDBusPendingReply<> reply = *call; if (reply.isError()) { - logger.error() << "Error received from the DBus service"; + logger.debug() << "DBus call failed (may be transient after systemd-resolved restart)"; } delete call; } @@ -223,23 +220,6 @@ 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 @@ -300,9 +280,15 @@ void DnsUtilsLinux::dnsDomainsReceived(QDBusPendingCallWatcher* call) { /* Add a root search domain for the new interface. */ if (m_ifindex > 0) { - QList newlist = {root}; - setLinkDomains(m_ifindex, newlist); - updateLinkDefaultRoutes(); + setLinkDomains(m_ifindex, {root}); + + /* Disable DefaultRoute on the physical gateway so systemd-resolved + * routes all DNS through the VPN interface. */ + const int gwIdx = NetworkUtilities::getGatewayAndIface().second.index(); + if (gwIdx > 0 && gwIdx != m_ifindex && gwIdx != m_gatewayIfindex) { + m_gatewayIfindex = gwIdx; + setLinkDefaultRoute(gwIdx, false); + } } } diff --git a/client/platforms/linux/daemon/dnsutilslinux.h b/client/platforms/linux/daemon/dnsutilslinux.h index f9f03b41e..cdc1492df 100644 --- a/client/platforms/linux/daemon/dnsutilslinux.h +++ b/client/platforms/linux/daemon/dnsutilslinux.h @@ -31,7 +31,6 @@ 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: @@ -42,9 +41,9 @@ class DnsUtilsLinux final : public DnsUtils { private: int m_ifindex = 0; + int m_gatewayIfindex = 0; int m_domainRetries = 0; QMap m_linkDomains; - QMap m_linkDefaultRoutes; QScopedPointer m_resolver; QString m_pendingIfname; QList m_pendingResolvers; From a53eb556b716dea7f335ffb80a59389959318704 Mon Sep 17 00:00:00 2001 From: NickVs2015 Date: Thu, 30 Apr 2026 17:30:59 +0300 Subject: [PATCH 7/7] fix: : add support new structure --- client/platforms/linux/daemon/dnsutilslinux.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/platforms/linux/daemon/dnsutilslinux.cpp b/client/platforms/linux/daemon/dnsutilslinux.cpp index e1f9e724e..133bc6b0a 100644 --- a/client/platforms/linux/daemon/dnsutilslinux.cpp +++ b/client/platforms/linux/daemon/dnsutilslinux.cpp @@ -11,7 +11,7 @@ #include #include -#include "core/networkUtilities.h" +#include "core/utils/networkUtilities.h" #include "leakdetector.h" #include "logger.h"