fix: Linux dns without dbus

This commit is contained in:
NickVs2015
2026-04-10 23:06:16 +03:00
parent 7c075625d2
commit 0f6db8a238
8 changed files with 194 additions and 251 deletions

View File

@@ -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);
}
}

View File

@@ -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;

View File

@@ -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

View File

@@ -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)

View File

@@ -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();

View File

@@ -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

View File

@@ -22,7 +22,7 @@ public:
bool isStrictKillSwitchEnabled();
private:
KillSwitch(QObject* parent) {};
explicit KillSwitch(QObject* parent) : QObject(parent) {}
QStringList m_allowedRanges;
QSharedPointer<SecureQSettings> m_appSettigns;

View File

@@ -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) {