File indexing completed on 2024-04-28 16:52:16

0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 // SPDX-FileCopyrightText: 2011 Craig Drummond <craig.p.drummond@gmail.com>
0003 // SPDX-FileCopyrightText: 2018 Alexis Lopes Zubeta <contact@azubieta.net>
0004 // SPDX-FileCopyrightText: 2020 Tomaz Canabrava <tcanabrava@kde.org>
0005 /*
0006  * UFW KControl Module
0007  */
0008 
0009 #include "firewallclient.h"
0010 
0011 #include "loglistmodel.h"
0012 #include "rulelistmodel.h"
0013 
0014 #include "ifirewallclientbackend.h"
0015 
0016 #include <KLocalizedString>
0017 #include <KPluginFactory>
0018 #include <KPluginMetaData>
0019 
0020 #include <QList>
0021 #include <QNetworkInterface>
0022 #include <QStringList>
0023 #include <QtGlobal>
0024 
0025 Q_LOGGING_CATEGORY(FirewallClientDebug, "firewall.client")
0026 
0027 IFirewallClientBackend *FirewallClient::m_currentBackend = nullptr;
0028 
0029 FirewallClient::FirewallClient(QObject *parent)
0030     : QObject(parent)
0031 {
0032 }
0033 
0034 FirewallClient::~FirewallClient() noexcept
0035 {
0036     m_currentBackend->deleteLater();
0037     m_currentBackend = nullptr;
0038 }
0039 
0040 QStringList FirewallClient::knownProtocols()
0041 {
0042     if (!m_currentBackend) {
0043         return {};
0044     }
0045     return m_currentBackend->knownProtocols();
0046 }
0047 
0048 bool FirewallClient::isTcpAndUdp(int protocolIdx)
0049 {
0050     if (!m_currentBackend) {
0051         return false;
0052     }
0053 
0054     return m_currentBackend->isTcpAndUdp(protocolIdx);
0055 }
0056 
0057 int FirewallClient::indexOfProtocol(const QString &protocol)
0058 {
0059     if (!m_currentBackend) {
0060         return -1;
0061     }
0062 
0063     const QStringList protocolList = m_currentBackend->knownProtocols();
0064     for (int i = 0; i < m_currentBackend->knownProtocols().size(); i++) {
0065         if (protocolList[i].toLower() == protocol.toLower()) {
0066             return i;
0067         }
0068     }
0069     return -1;
0070 }
0071 
0072 QStringList FirewallClient::knownInterfaces()
0073 {
0074     QStringList interface_names({i18n("Any")});
0075 
0076     for (const QNetworkInterface &iface : QNetworkInterface::allInterfaces()) {
0077         interface_names << iface.name();
0078     }
0079 
0080     return interface_names;
0081 }
0082 
0083 void FirewallClient::refresh()
0084 {
0085     if (!m_currentBackend) {
0086         return;
0087     }
0088     m_currentBackend->refresh();
0089 }
0090 
0091 RuleListModel *FirewallClient::rulesModel() const
0092 {
0093     if (!m_currentBackend) {
0094         return nullptr;
0095     }
0096     return m_currentBackend->rules();
0097 }
0098 
0099 Rule *FirewallClient::ruleAt(int index)
0100 {
0101     if (!m_currentBackend) {
0102         return nullptr;
0103     }
0104     return m_currentBackend->ruleAt(index);
0105 }
0106 
0107 KJob *FirewallClient::addRule(Rule *rule)
0108 {
0109     if (!m_currentBackend) {
0110         return nullptr;
0111     }
0112 
0113     if (!m_currentBackend->isCurrentlyLoaded()) {
0114         return nullptr;
0115     }
0116 
0117     return m_currentBackend->addRule(rule);
0118 }
0119 
0120 KJob *FirewallClient::removeRule(int index)
0121 {
0122     if (!m_currentBackend) {
0123         return nullptr;
0124     }
0125     if (!m_currentBackend->isCurrentlyLoaded()) {
0126         return nullptr;
0127     }
0128     return m_currentBackend->removeRule(index);
0129 }
0130 
0131 KJob *FirewallClient::updateRule(Rule *rule)
0132 {
0133     if (!m_currentBackend) {
0134         return nullptr;
0135     }
0136     if (!m_currentBackend->isCurrentlyLoaded()) {
0137         return nullptr;
0138     }
0139     return m_currentBackend->updateRule(rule);
0140 }
0141 
0142 KJob *FirewallClient::moveRule(int from, int to)
0143 {
0144     // TODO: Verify if this method is needed.
0145     if (!m_currentBackend) {
0146         return nullptr;
0147     }
0148     return m_currentBackend->moveRule(from, to);
0149 }
0150 
0151 KJob *FirewallClient::save()
0152 {
0153     if (!m_currentBackend) {
0154         return nullptr;
0155     }
0156     return m_currentBackend->save();
0157 }
0158 
0159 QString FirewallClient::name() const
0160 {
0161     if (!m_currentBackend) {
0162         return {};
0163     }
0164     return m_currentBackend->name();
0165 }
0166 FirewallClient::Capabilities FirewallClient::capabilities() const
0167 {
0168     if (!m_currentBackend) {
0169         return FirewallClient::Capability::None;
0170     }
0171     return m_currentBackend->capabilities();
0172 }
0173 
0174 /* Creates a new Rule and returns it to the Qml side, passing arguments based
0175  * on the Connection Table. */
0176 Rule *FirewallClient::createRuleFromConnection(const QString &protocol, const QString &localAddress, const QString &foreignAddres, const QString &status)
0177 {
0178     if (!m_currentBackend) {
0179         return nullptr;
0180     }
0181     return m_currentBackend->createRuleFromConnection(protocol, localAddress, foreignAddres, status);
0182 }
0183 
0184 Rule *FirewallClient::createRuleFromLog(const QString &protocol,
0185                                         const QString &sourceAddress,
0186                                         const QString &sourcePort,
0187                                         const QString &destinationAddress,
0188                                         const QString &destinationPort,
0189                                         const QString &inn)
0190 {
0191     if (!m_currentBackend) {
0192         return nullptr;
0193     }
0194     return m_currentBackend->createRuleFromLog(protocol, sourceAddress, sourcePort, destinationAddress, destinationPort, inn);
0195 }
0196 
0197 bool FirewallClient::enabled() const
0198 {
0199     if (!m_currentBackend) {
0200         return false;
0201     }
0202     return m_currentBackend->enabled();
0203 }
0204 
0205 QString FirewallClient::defaultIncomingPolicy() const
0206 {
0207     if (!m_currentBackend) {
0208         return {};
0209     }
0210     return m_currentBackend->defaultIncomingPolicy();
0211 }
0212 
0213 QString FirewallClient::defaultOutgoingPolicy() const
0214 {
0215     if (!m_currentBackend) {
0216         return {};
0217     }
0218     return m_currentBackend->defaultOutgoingPolicy();
0219 }
0220 
0221 LogListModel *FirewallClient::logsModel() const
0222 {
0223     // TODO: Perhaps this function is uneeded.
0224     if (!m_currentBackend) {
0225         return nullptr;
0226     }
0227     return m_currentBackend->logs();
0228 }
0229 
0230 bool FirewallClient::logsAutoRefresh() const
0231 {
0232     if (!m_currentBackend) {
0233         return false;
0234     }
0235     return m_currentBackend->logsAutoRefresh();
0236 }
0237 
0238 KJob *FirewallClient::setEnabled(bool enabled)
0239 {
0240     if (!m_currentBackend) {
0241         return nullptr;
0242     }
0243     return m_currentBackend->setEnabled(enabled);
0244 }
0245 
0246 void FirewallClient::queryStatus(DefaultDataBehavior defaultsBehavior, ProfilesBehavior profilesBehavior)
0247 {
0248     if (!m_currentBackend) {
0249         return;
0250     }
0251     m_currentBackend->queryStatus(defaultsBehavior, profilesBehavior);
0252 }
0253 
0254 KJob *FirewallClient::setDefaultIncomingPolicy(const QString &defaultIncomingPolicy)
0255 {
0256     if (!m_currentBackend) {
0257         return nullptr;
0258     }
0259     if (!m_currentBackend->isCurrentlyLoaded()) {
0260         return nullptr;
0261     }
0262     return m_currentBackend->setDefaultIncomingPolicy(defaultIncomingPolicy);
0263 }
0264 
0265 KJob *FirewallClient::setDefaultOutgoingPolicy(const QString &defaultOutgoingPolicy)
0266 {
0267     if (!m_currentBackend) {
0268         return nullptr;
0269     }
0270     if (!m_currentBackend->isCurrentlyLoaded()) {
0271         return nullptr;
0272     }
0273     return m_currentBackend->setDefaultOutgoingPolicy(defaultOutgoingPolicy);
0274 }
0275 
0276 void FirewallClient::setLogsAutoRefresh(bool logsAutoRefresh)
0277 {
0278     if (!m_currentBackend) {
0279         return;
0280     }
0281     m_currentBackend->setLogsAutoRefresh(logsAutoRefresh);
0282 }
0283 
0284 bool FirewallClient::hasExecutable() const
0285 {
0286     if (!m_currentBackend) {
0287         return false;
0288     }
0289     return m_currentBackend->hasExecutable();
0290 }
0291 
0292 void FirewallClient::setBackend(const QStringList &backendList)
0293 {
0294     if (m_currentBackend) {
0295         Q_EMIT enabledChanged(false);
0296         delete m_currentBackend;
0297         m_currentBackend = nullptr;
0298     }
0299     // cppcheck-suppress unknownMacro
0300     const auto plugins = KPluginMetaData::findPlugins(QStringLiteral("kf" QT_STRINGIFY(QT_VERSION_MAJOR) "/plasma_firewall"));
0301 
0302     QList<KPluginFactory *> factories;
0303     for (const KPluginMetaData &metadata : plugins) {
0304         QString pluginName = metadata.pluginId().remove(QStringLiteral("backend"));
0305         if (!backendList.contains(pluginName)) {
0306             continue;
0307         }
0308         KPluginFactory *factory = KPluginFactory::loadFactory(metadata).plugin;
0309         if (!factory) {
0310             continue;
0311         }
0312         factories.append(factory);
0313     }
0314 
0315     // lambdas
0316     auto systemCheck = [this](const QList<KPluginFactory *> &factories) -> IFirewallClientBackend * {
0317         for (KPluginFactory *factory : factories) {
0318             auto perhaps = factory->create<IFirewallClientBackend>(this, QVariantList());
0319             if (perhaps->isCurrentlyLoaded()) {
0320                 return perhaps;
0321             }
0322             perhaps->deleteLater();
0323         }
0324         return nullptr;
0325     };
0326 
0327     auto loadFromBinary = [this](const QList<KPluginFactory *> factories) -> IFirewallClientBackend * {
0328         for (KPluginFactory *factory : factories) {
0329             auto perhaps = factory->create<IFirewallClientBackend>(this, QVariantList());
0330             if (perhaps->hasExecutable()) {
0331                 return perhaps;
0332             }
0333             perhaps->deleteLater();
0334         }
0335         return nullptr;
0336     };
0337 
0338     m_currentBackend = systemCheck(factories);
0339     if (!m_currentBackend) {
0340         m_currentBackend = loadFromBinary(factories);
0341     }
0342 
0343     if (!m_currentBackend) {
0344         qCDebug(FirewallClientDebug) << "Could not find any of the specified backends" << backendList;
0345         return;
0346     }
0347 
0348     connect(m_currentBackend, &IFirewallClientBackend::enabledChanged, this, &FirewallClient::enabledChanged);
0349     connect(m_currentBackend, &IFirewallClientBackend::defaultIncomingPolicyChanged, this, &FirewallClient::defaultIncomingPolicyChanged);
0350     connect(m_currentBackend, &IFirewallClientBackend::defaultOutgoingPolicyChanged, this, &FirewallClient::defaultOutgoingPolicyChanged);
0351     connect(m_currentBackend, &IFirewallClientBackend::logsAutoRefreshChanged, this, &FirewallClient::logsAutoRefreshChanged);
0352     connect(m_currentBackend, &IFirewallClientBackend::hasExecutableChanged, this, &FirewallClient::hasExecutableChanged);
0353     connect(m_currentBackend, &IFirewallClientBackend::showErrorMessage, this, &FirewallClient::showErrorMessage);
0354 }
0355 
0356 QString FirewallClient::backend() const
0357 {
0358     if (!m_currentBackend) {
0359         return {};
0360     }
0361     return m_currentBackend->name();
0362 }
0363 
0364 QString FirewallClient::version() const
0365 {
0366     if (!m_currentBackend) {
0367         return {};
0368     }
0369     return m_currentBackend->version();
0370 }
0371 
0372 bool FirewallClient::supportsRuleUpdate() const
0373 {
0374     if (!m_currentBackend) {
0375         return false;
0376     }
0377     return m_currentBackend->supportsRuleUpdate();
0378 }
0379 
0380 QStringList FirewallClient::knownApplications()
0381 {
0382     if (!m_currentBackend) {
0383         return {};
0384     }
0385 
0386     return m_currentBackend->knownApplications();
0387 }
0388 
0389 #include "moc_firewallclient.cpp"