File indexing completed on 2024-04-28 16:52:17
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 "rule.h" 0010 #include "appprofiles.h" 0011 #include "firewallclient.h" 0012 #include <KLocalizedString> 0013 #include <QByteArray> 0014 #include <QMap> 0015 #include <QTextStream> 0016 #include <arpa/inet.h> 0017 #include <netdb.h> 0018 0019 #include "firewallclient.h" 0020 0021 // Keep in sync with kcm_ufw_helper.py 0022 static const char *ANY_ADDR = "0.0.0.0/0"; 0023 static const char *ANY_ADDR_V6 = "::/0"; 0024 static const char *ANY_PORT = "any"; 0025 0026 // Shorten an IPv6 address (if applicable) 0027 static QString shortenAddress(const QString &addr) 0028 { 0029 if (!addr.contains(":")) { 0030 return addr; 0031 } 0032 QByteArray bytes(addr.toLatin1()); 0033 unsigned char num[16]; 0034 0035 if (inet_pton(AF_INET6, bytes.constData(), num) > 0) { 0036 char conv[41]; 0037 if (NULL != inet_ntop(AF_INET6, num, conv, 41)) { 0038 return QLatin1String(conv); 0039 } 0040 } 0041 return addr; 0042 } 0043 0044 static QString addIface(const QString &orig, const QString &iface) 0045 { 0046 return iface.isEmpty() ? orig : i18nc("address on interface", "%1 on %2", orig, iface); 0047 } 0048 0049 static QString serviceName(short port) 0050 { 0051 static QMap<int, QString> serviceMap; 0052 0053 if (serviceMap.contains(port)) { 0054 return serviceMap[port]; 0055 } 0056 0057 struct servent *ent = getservbyport(htons(port), 0L); 0058 0059 if (ent && ent->s_name) { 0060 serviceMap[port] = ent->s_name; 0061 return serviceMap[port]; 0062 } 0063 0064 return {}; 0065 } 0066 0067 static QString formatPort(const QString &port, int prot) 0068 { 0069 return port.isEmpty() ? Rule::protocolSuffix(prot, QString()) : port + Rule::protocolSuffix(prot); 0070 } 0071 0072 static QString modifyAddress(const QString &addr, const QString &port) 0073 { 0074 if (addr.isEmpty() || ANY_ADDR == addr || ANY_ADDR_V6 == addr) { 0075 return port.isEmpty() ? i18n("Anywhere") : QString(); 0076 } 0077 0078 return shortenAddress(addr); 0079 } 0080 0081 static QString modifyPort(const QString &port, int prot, bool matchPortNoProto = false) 0082 { 0083 if (port.isEmpty()) { 0084 return port; 0085 } 0086 // Does it match a pre-configured application? 0087 Types::PredefinedPort pp = Types::toPredefinedPort(port + Rule::protocolSuffix(prot)); 0088 0089 // When matching glog lines, the protocol is *always* specified - but don't always want this when 0090 // matching names... 0091 if (matchPortNoProto && Types::PP_COUNT == pp) { 0092 pp = Types::toPredefinedPort(port); 0093 } 0094 0095 if (Types::PP_COUNT != pp) { 0096 return i18nc("service/application name (port numbers)", "%1 (%2)", Types::toString(pp, true), port + Rule::protocolSuffix(prot)); 0097 } 0098 0099 // Is it a service known to /etc/services ??? 0100 bool ok(false); 0101 QString service; 0102 short portNum = port.toShort(&ok); 0103 0104 if (ok) { 0105 service = serviceName(portNum); 0106 } 0107 0108 if (!service.isEmpty()) { 0109 return i18nc("service/application name (port numbers)", "%1 (%2)", service, formatPort(port, prot)); 0110 } 0111 0112 // Just return port/servicename and protocol 0113 return formatPort(port, prot); 0114 } 0115 0116 static QString modifyApp(const QString &app, const QString &port, int prot) 0117 { 0118 if (app.isEmpty()) { 0119 return port; 0120 } 0121 0122 // TODO: Send the profile, not the app name. 0123 Entry profile({}); 0124 // Entry profile(get(app)); 0125 0126 return i18nc("service/application name (port numbers)", "%1 (%2)", app, profile.name.isEmpty() ? formatPort(port, prot) : profile.ports); 0127 } 0128 0129 int Rule::servicePort(const QString &name) 0130 { 0131 static QMap<QString, int> serviceMap; 0132 0133 if (serviceMap.contains(name)) { 0134 return serviceMap[name]; 0135 } 0136 0137 QByteArray l1 = name.toLatin1(); 0138 struct servent *ent = getservbyname(l1.constData(), 0L); 0139 0140 if (ent && ent->s_name) { 0141 serviceMap[name] = ntohs(ent->s_port); 0142 return serviceMap[name]; 0143 } 0144 0145 return 0; 0146 } 0147 0148 QString Rule::protocolSuffix(int prot, const QString &sep) 0149 { 0150 if (FirewallClient::isTcpAndUdp(prot)) { 0151 return {}; 0152 } 0153 0154 if (prot == -1) { 0155 prot = 0; 0156 qWarning() << "Invalid protocol -1, defaulting to" << FirewallClient::knownProtocols().at(prot); 0157 } 0158 0159 return sep + FirewallClient::knownProtocols().at(prot); 0160 } 0161 0162 QString Rule::modify(const QString &address, const QString &port, const QString &application, const QString &iface, int protocol, bool matchPortNoProto) 0163 { 0164 if ((port == ANY_PORT || port.isEmpty()) && (address.isEmpty() || ANY_ADDR == address || ANY_ADDR_V6 == address)) 0165 return addIface(i18n("Anywhere"), iface); 0166 0167 bool isAnyAddress = address.isEmpty() || ANY_ADDR == address || ANY_ADDR_V6 == address, isAnyPort = port.isEmpty() || ANY_PORT == port; 0168 QString bPort = application.isEmpty() ? modifyPort(port, protocol, matchPortNoProto) : modifyApp(application, port, protocol), 0169 bAddr = modifyAddress(address, port); 0170 0171 return addIface(isAnyAddress ? isAnyPort ? i18n("Anywhere") : bPort : bAddr.isEmpty() ? bPort : bAddr + QChar(' ') + bPort, iface); 0172 } 0173 0174 Rule::Rule() 0175 : m_position(0) 0176 , m_action(Types::POLICY_REJECT) 0177 , m_incoming(true) 0178 , m_ipv6(false) 0179 , m_simplified(true) 0180 , m_protocol(0) 0181 , m_logtype(Types::LOGGING_OFF) 0182 , m_interface(0) 0183 { 0184 } 0185 0186 QString Rule::fromStr() const 0187 { 0188 /* qDebug() << "Before Crashing" << m_protocol; */ 0189 return modify(m_sourceAddress, m_sourcePort, m_sourceApplication, m_interfaceIn, m_protocol); 0190 } 0191 0192 QString Rule::toStr() const 0193 { 0194 return modify(m_destAddress, m_destPort, m_destApplication, m_interfaceOut, m_protocol); 0195 } 0196 0197 QString Rule::actionStr() const 0198 { 0199 return m_incoming ? i18nc("firewallAction incoming", "%1 incoming", Types::toString(m_action, true)) 0200 : i18nc("firewallAction outgoing", "%1 outgoing", Types::toString(m_action, true)); 0201 } 0202 0203 QString Rule::ipV6Str() const 0204 { 0205 return m_ipv6 ? i18n("Yes") : QString(); 0206 } 0207 0208 QString Rule::loggingStr() const 0209 { 0210 return Types::toString(m_logtype, false); 0211 } 0212 0213 void Rule::setPolicy(const QString &policy) 0214 { 0215 auto policy_t = Types::toPolicy(policy); 0216 0217 if (policy_t == action()) { 0218 return; 0219 } 0220 0221 m_action = policy_t; 0222 Q_EMIT policyChanged(policy); 0223 } 0224 0225 void Rule::setIncoming(bool incoming) 0226 { 0227 if (m_incoming == incoming) { 0228 return; 0229 } 0230 0231 m_incoming = incoming; 0232 Q_EMIT incomingChanged(incoming); 0233 } 0234 0235 void Rule::setSourceAddress(const QString &sourceAddress) 0236 { 0237 if (m_sourceAddress == sourceAddress) { 0238 return; 0239 } 0240 m_sourceAddress = sourceAddress; 0241 Q_EMIT sourceAddressChanged(sourceAddress); 0242 } 0243 0244 void Rule::setSourcePort(const QString &sourcePort) 0245 { 0246 if (m_sourcePort == sourcePort) { 0247 return; 0248 } 0249 0250 m_sourcePort = sourcePort; 0251 Q_EMIT sourcePortChanged(sourcePort); 0252 } 0253 0254 void Rule::setDestinationAddress(const QString &destinationAddress) 0255 { 0256 if (m_destAddress == destinationAddress) { 0257 return; 0258 } 0259 m_destAddress = destinationAddress; 0260 Q_EMIT destinationAddressChanged(destinationAddress); 0261 } 0262 0263 void Rule::setDestinationPort(const QString &destinationPort) 0264 { 0265 if (m_destPort == destinationPort) { 0266 return; 0267 } 0268 0269 m_destPort = destinationPort; 0270 Q_EMIT destinationPortChanged(destinationPort); 0271 } 0272 0273 void Rule::setIpv6(bool ipv6) 0274 { 0275 if (m_ipv6 == ipv6) { 0276 return; 0277 } 0278 0279 m_ipv6 = ipv6; 0280 Q_EMIT ipv6Changed(ipv6); 0281 } 0282 0283 void Rule::setProtocol(int v) 0284 { 0285 Q_ASSERT(v != -1); 0286 m_protocol = v; 0287 } 0288 0289 void Rule::setInterface(int interface) 0290 { 0291 if (m_interface == interface) { 0292 return; 0293 } 0294 0295 m_interfaceStr = interface != 0 ? FirewallClient::knownInterfaces().at(interface) : QString(); 0296 m_interface = interface; 0297 0298 Q_EMIT interfaceChanged(interface); 0299 } 0300 0301 void Rule::setLogging(const QString &logging) 0302 { 0303 auto logging_t = Types::toLogging(logging); 0304 if (m_logtype == logging_t) { 0305 return; 0306 } 0307 0308 m_logtype = logging_t; 0309 Q_EMIT loggingChanged(logging); 0310 } 0311 0312 void Rule::setPosition(int position) 0313 { 0314 if (m_position == position) { 0315 return; 0316 } 0317 0318 m_position = position; 0319 Q_EMIT positionChanged(position); 0320 } 0321 0322 QString Rule::policy() const 0323 { 0324 return Types::toString(action()); 0325 } 0326 0327 QString Rule::destinationAddress() const 0328 { 0329 return m_destAddress; 0330 } 0331 0332 QString Rule::interfaceStr() const 0333 { 0334 return m_interfaceStr; 0335 } 0336 0337 int Rule::interface() const 0338 { 0339 return m_interface; 0340 } 0341 0342 QString Rule::destinationPort() const 0343 { 0344 return m_destPort; 0345 } 0346 0347 int Rule::position() const 0348 { 0349 return m_position; 0350 } 0351 Types::Policy Rule::action() const 0352 { 0353 return m_action; 0354 } 0355 bool Rule::incoming() const 0356 { 0357 return m_incoming; 0358 } 0359 bool Rule::ipv6() const 0360 { 0361 return m_ipv6; 0362 } 0363 0364 int Rule::protocol() const 0365 { 0366 return m_protocol; 0367 } 0368 0369 QString Rule::sourceApplication() const 0370 { 0371 return m_sourceApplication; 0372 } 0373 0374 QString Rule::sourceAddress() const 0375 { 0376 return m_sourceAddress; 0377 } 0378 QString Rule::sourcePort() const 0379 { 0380 return m_sourcePort; 0381 } 0382 QString Rule::interfaceIn() const 0383 { 0384 return m_interfaceIn; 0385 } 0386 QString Rule::interfaceOut() const 0387 { 0388 return m_interfaceOut; 0389 } 0390 0391 Types::Logging Rule::logging() const 0392 { 0393 return m_logtype; 0394 } 0395 0396 void Rule::setV6(const bool v) 0397 { 0398 m_ipv6 = v; 0399 } 0400 0401 QString Rule::destinationApplication() const 0402 { 0403 return m_destApplication; 0404 } 0405 0406 void Rule::setSimplified(bool value) 0407 { 0408 if (m_simplified == value) { 0409 return; 0410 } 0411 m_simplified = value; 0412 Q_EMIT simplifiedChanged(value); 0413 } 0414 0415 void Rule::setSourceApplication(const QString &app) 0416 { 0417 if (m_sourceApplication == app) { 0418 return; 0419 } 0420 m_sourceApplication = app; 0421 Q_EMIT sourceApplicationChanged(app); 0422 } 0423 bool Rule::simplified() const 0424 { 0425 return m_simplified; 0426 }