fix: Dbus error, fix race conditional

This commit is contained in:
NickVs2015
2026-03-31 10:35:04 +03:00
parent 316e64122e
commit bd554fb730
5 changed files with 55 additions and 7 deletions

View File

@@ -7,6 +7,7 @@
#include <net/if.h>
#include <QDBusVariant>
#include <QTimer>
#include <QtDBus/QtDBus>
#include "leakdetector.h"
@@ -58,6 +59,7 @@ bool DnsUtilsLinux::updateResolvers(const QString& ifname,
return false;
}
m_resolvers = resolvers;
setLinkDNS(m_ifindex, resolvers);
setLinkDefaultRoute(m_ifindex, true);
updateLinkDomains();
@@ -90,7 +92,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;
}
@@ -174,11 +176,25 @@ void DnsUtilsLinux::updateLinkDomains() {
void DnsUtilsLinux::dnsDomainsReceived(QDBusPendingCallWatcher* call) {
QDBusPendingReply<QVariant> reply = *call;
delete call;
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_domainRetries++ < 5) {
logger.debug() << "systemd-resolved not ready yet, retrying DNS setup ("
<< m_domainRetries << "/5)";
// Re-apply DNS servers and default route in case systemd-resolved lost them on restart
if (m_ifindex > 0 && !m_resolvers.isEmpty()) {
setLinkDNS(m_ifindex, m_resolvers);
setLinkDefaultRoute(m_ifindex, true);
}
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();
@@ -206,7 +222,6 @@ void DnsUtilsLinux::dnsDomainsReceived(QDBusPendingCallWatcher* call) {
/* Add a root search domain for the new interface. */
QList<DnsLinkDomain> newlist = {root};
setLinkDomains(m_ifindex, newlist);
delete call;
}
static DnsMetatypeRegistrationProxy s_dnsMetatypeProxy;

View File

@@ -34,6 +34,8 @@ class DnsUtilsLinux final : public DnsUtils {
private:
int m_ifindex = 0;
int m_domainRetries = 0;
QList<QHostAddress> m_resolvers;
QMap<int, DnsLinkDomainList> m_linkDomains;
QDBusInterface* m_resolver = nullptr;
};

View File

@@ -108,7 +108,7 @@ int LinuxFirewall::linkChain(LinuxFirewall::IPVersion ip, const QString& chain,
// (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
// 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
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));
@@ -289,6 +289,7 @@ void LinuxFirewall::install()
installAnchor(Both, QStringLiteral("100.blockAll"), {
QStringLiteral("-j REJECT"),
});
installAnchor(Both, QStringLiteral("400.allowPIA"), {});
// NAT rules
installAnchor(Both, QStringLiteral("100.transIp"), {
@@ -495,13 +496,23 @@ int LinuxFirewall::execute(const QString &command, bool ignoreErrors)
logger.debug() << "(" << exitCode << ") $ " << command;
if (!out.isEmpty())
logger.info() << out;
if (!err.isEmpty())
if (!err.isEmpty() && !ignoreErrors)
logger.warning() << err;
return exitCode;
}
void LinuxFirewall::setupTrafficSplitting()
{
// Register the routing table name so the ip tool can resolve it by name
execute(QStringLiteral("grep -q '%1' /etc/iproute2/rt_tables || printf '200\\t%1\\n' >> /etc/iproute2/rt_tables").arg(kRtableName));
// On cgroup v2 (unified hierarchy) systems /sys/fs/cgroup/net_cls/ does not exist.
// Try to mount the legacy net_cls cgroup v1 controller so traffic splitting works.
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/";
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));
@@ -513,6 +524,9 @@ void LinuxFirewall::teardownTrafficSplitting()
{
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("ip route flush table %1").arg(kRtableName));
// Ignore errors here: on first teardown the table name may not be registered yet
execute(QStringLiteral("ip route flush table %1").arg(kRtableName), true);
execute(QStringLiteral("ip route flush cache"));
// Remove the rt_tables entry we added
execute(QStringLiteral("sed -i '/%1/d' /etc/iproute2/rt_tables").arg(kRtableName));
}

View File

@@ -65,10 +65,18 @@ bool WireguardUtilsLinux::addInterface(const InterfaceConfig& config) {
return false;
}
// Kill any orphaned wireguard-go process from a previous crash that may
// still hold the amn0 TUN device, then delete the stale interface.
QProcess::execute("pkill", {"-f", QString("wireguard-go.*%1").arg(WG_INTERFACE)});
QProcess::execute("ip", {"link", "delete", WG_INTERFACE});
QDir wgRuntimeDir(WG_RUNTIME_DIR);
if (!wgRuntimeDir.exists()) {
wgRuntimeDir.mkpath(".");
}
// Remove stale runtime files from a previous session.
QFile::remove(wgRuntimeDir.filePath(QString(WG_INTERFACE) + ".name"));
QFile::remove(wgRuntimeDir.filePath(QString(WG_INTERFACE) + ".sock"));
QProcessEnvironment pe = QProcessEnvironment::systemEnvironment();
QString wgNameFile = wgRuntimeDir.filePath(QString(WG_INTERFACE) + ".sock");

View File

@@ -122,6 +122,15 @@ void LinuxNetworkWatcherWorker::initialize() {
SLOT(propertyChanged(QString, QVariantMap, QStringList)));
}
// Seed m_previousNMState with the current NM state so that a transient
// drop from CONNECTED_GLOBAL (70) to CONNECTED_SITE (60) caused by the
// VPN's DNS setup does not look like a reconnection from offline.
QVariant currentState = nm.property("State");
if (currentState.isValid()) {
m_previousNMState = currentState.toUInt();
logger.debug() << "Initial NM state:" << m_previousNMState;
}
QDBusConnection::systemBus().connect(DBUS_NETWORKMANAGER,
DBUS_NETWORKMANAGER_PATH,
DBUS_NETWORKMANAGER,