NetworkManagerQt

utils.cpp
1/*
2 SPDX-FileCopyrightText: 2009 Will Stephenson <wstephenson@kde.org>
3 SPDX-FileCopyrightText: 2012-2013 Jan Grulich <jgrulich@redhat.com>
4
5 SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
6*/
7
8#include <QRegularExpression>
9
10#include "time.h"
11#include "utils.h"
12
14{
15 // Q_ASSERT(address.size() == 16);
16 Q_IPV6ADDR tmp;
17 for (int i = 0; i < 16; ++i) {
18 tmp[i] = address[i];
19 }
20 QHostAddress hostaddress(tmp);
21 Q_ASSERT(hostaddress.protocol() == QAbstractSocket::IPv6Protocol);
22
23 return hostaddress;
24}
25
27{
28 // Q_ASSERT(address.protocol() == QAbstractSocket::IPv6Protocol);
29 Q_IPV6ADDR tmp = address.toIPv6Address();
30 QByteArray assembledAddress;
31 assembledAddress.reserve(16);
32 for (int i = 0; i < 16; ++i) {
33 assembledAddress.push_back(tmp[i]);
34 }
35
36 return assembledAddress;
37}
38
40{
41 QStringList mac;
42
43 for (int i = 0; i < ba.size(); ++i) {
44 mac << QString("%1").arg((quint8)ba[i], 2, 16, QLatin1Char('0')).toUpper();
45 }
46
47 return mac.join(":");
48}
49
51{
52 const QStringList macStringList = s.split(':');
53 // Q_ASSERT(macStringList.size() == 6);
54 QByteArray ba;
55 if (!s.isEmpty()) {
56 ba.resize(6);
57 int i = 0;
58
59 for (const QString &macPart : macStringList) {
60 ba[i++] = macPart.toUInt(nullptr, 16);
61 }
62 }
63 return ba;
64}
65
66bool NetworkManager::macAddressIsValid(const QString &macAddress)
67{
68 QRegularExpression macAddressCheck(QStringLiteral("([a-fA-F0-9][a-fA-F0-9]:){5}[0-9a-fA-F][0-9a-fA-F]"));
69
70 return macAddressCheck.match(macAddress).hasMatch();
71}
72
73bool NetworkManager::macAddressIsValid(const QByteArray &macAddress)
74{
75 return macAddressIsValid(macAddressAsString(macAddress));
76}
77
79{
80 int channel;
81 if (freq < 2500) {
82 channel = 0;
83 int i = 0;
84 QList<QPair<int, int>> bFreqs = getBFreqs();
85 while (i < bFreqs.size()) {
86 if (bFreqs.at(i).second <= freq) {
87 channel = bFreqs.at(i).first;
88 } else {
89 break;
90 }
91 i++;
92 }
93 return channel;
94 }
95 channel = 0;
96 int i = 0;
97 QList<QPair<int, int>> aFreqs = getAFreqs();
98 while (i < aFreqs.size()) {
99 if (aFreqs.at(i).second <= freq) {
100 channel = aFreqs.at(i).first;
101 if (aFreqs.at(i).second == freq) {
102 break;
103 }
104 } else {
105 break;
106 }
107 i++;
108 }
109
110 return channel;
111}
112
113NetworkManager::WirelessSetting::FrequencyBand NetworkManager::findFrequencyBand(int freq)
114{
115 if (freq < 2500) {
116 return WirelessSetting::Bg;
117 }
118
119 return WirelessSetting::A;
120}
121
122bool NetworkManager::deviceSupportsApCiphers(NetworkManager::WirelessDevice::Capabilities interfaceCaps,
124 WirelessSecurityType type)
125{
126 bool havePair = false;
127 bool haveGroup = true;
128
129 if (type == NetworkManager::StaticWep) {
130 havePair = true;
131 } else {
132 if (interfaceCaps.testFlag(NetworkManager::WirelessDevice::Wep40) && apCiphers.testFlag(NetworkManager::AccessPoint::PairWep40)) {
133 havePair = true;
134 }
135 if (interfaceCaps.testFlag(NetworkManager::WirelessDevice::Wep104) && apCiphers.testFlag(NetworkManager::AccessPoint::PairWep104)) {
136 havePair = true;
137 }
138 if (interfaceCaps.testFlag(NetworkManager::WirelessDevice::Tkip) && apCiphers.testFlag(NetworkManager::AccessPoint::PairTkip)) {
139 havePair = true;
140 }
141 if (interfaceCaps.testFlag(NetworkManager::WirelessDevice::Ccmp) && apCiphers.testFlag(NetworkManager::AccessPoint::PairCcmp)) {
142 havePair = true;
143 }
144 }
145
146 if (interfaceCaps.testFlag(NetworkManager::WirelessDevice::Wep40) && apCiphers.testFlag(NetworkManager::AccessPoint::GroupWep40)) {
147 haveGroup = true;
148 }
149 if (interfaceCaps.testFlag(NetworkManager::WirelessDevice::Wep104) && apCiphers.testFlag(NetworkManager::AccessPoint::GroupWep104)) {
150 haveGroup = true;
151 }
152 if (type != StaticWep) {
153 if (interfaceCaps.testFlag(NetworkManager::WirelessDevice::Tkip) && apCiphers.testFlag(NetworkManager::AccessPoint::GroupTkip)) {
154 haveGroup = true;
155 }
156 if (interfaceCaps.testFlag(NetworkManager::WirelessDevice::Ccmp) && apCiphers.testFlag(NetworkManager::AccessPoint::GroupCcmp)) {
157 haveGroup = true;
158 }
159 }
160
161 return (havePair && haveGroup);
162}
163
164// Keep this in sync with NetworkManager/libnm-core/nm-utils.c:nm_utils_security_valid()
165bool NetworkManager::securityIsValid(WirelessSecurityType type,
167 bool haveAp,
168 bool adhoc,
172{
173 bool good = true;
174
175 // kDebug() << "type(" << type << ") interfaceCaps(" << interfaceCaps << ") haveAp(" << haveAp << ") adhoc(" << adhoc << ") apCaps(" << apCaps << ") apWpa("
176 // << apWpa << " apRsn(" << apRsn << ")";
177
178 if (!haveAp) {
179 if (type == NoneSecurity) {
180 return true;
181 }
182 if ((type == StaticWep) //
183 || ((type == DynamicWep) && !adhoc) //
184 || ((type == Leap) && !adhoc)) {
186 return true;
187 } else {
188 return false;
189 }
190 }
191
192 // apCaps.testFlag(Privacy) == true for StaticWep, Leap and DynamicWep
193 // see libs/internals/wirelessinterfaceconnectionhelpers.cpp
194
195 // TODO: this is not in nm-utils.c
196 // if (type == Knm::WirelessSecurity::WpaPsk
197 // || ((type == Knm::WirelessSecurity::WpaEap) && !adhoc)) {
198 // if (interfaceCaps.testFlag(NetworkManager::WirelessDevice::Wpa) &&
199 // !apCaps.testFlag(NetworkManager::AccessPoint::Privacy)) {
200 // return true;
201 // }
202 // }
203 // if (type == Knm::WirelessSecurity::Wpa2Psk
204 // || ((type == Knm::WirelessSecurity::Wpa2Eap) && !adhoc)) {
205 // if (interfaceCaps.testFlag(NetworkManager::WirelessDevice::Rsn) &&
206 // !apCaps.testFlag(NetworkManager::AccessPoint::Privacy)) {
207 // return true;
208 // }
209 // }
210 }
211
212 switch (type) {
213 case NoneSecurity:
214 Q_ASSERT(haveAp);
216 return false;
217 }
218 if (apWpa || apRsn) {
219 return false;
220 }
221 break;
222 case Leap: /* require PRIVACY bit for LEAP? */
223 if (adhoc) {
224 return false;
225 }
226 /* Fall through */
227 case StaticWep:
228 Q_ASSERT(haveAp);
230 return false;
231 }
232 if (apWpa || apRsn) {
233 if (!deviceSupportsApCiphers(interfaceCaps, apWpa, StaticWep)) {
234 if (!deviceSupportsApCiphers(interfaceCaps, apRsn, StaticWep)) {
235 return false;
236 }
237 }
238 }
239 break;
240 case DynamicWep:
241 if (adhoc) {
242 return false;
243 }
244 Q_ASSERT(haveAp);
245 if (apRsn || !(apCaps.testFlag(NetworkManager::AccessPoint::Privacy))) {
246 return false;
247 }
248 /* Some APs broadcast minimal WPA-enabled beacons that must be handled */
249 if (apWpa) {
250 if (!apWpa.testFlag(NetworkManager::AccessPoint::KeyMgmt8021x)) {
251 return false;
252 }
253 if (!deviceSupportsApCiphers(interfaceCaps, apWpa, DynamicWep)) {
254 return false;
255 }
256 }
257 break;
258 case WpaPsk:
259 if (adhoc) {
260 return false;
261 }
262
263 if (!interfaceCaps.testFlag(NetworkManager::WirelessDevice::Wpa)) {
264 return false;
265 }
266 if (haveAp) {
267 if (apWpa.testFlag(NetworkManager::AccessPoint::KeyMgmtPsk)) {
268 if (apWpa.testFlag(NetworkManager::AccessPoint::PairTkip) //
270 return true;
271 }
272 if (apWpa.testFlag(NetworkManager::AccessPoint::PairCcmp) //
274 return true;
275 }
276 }
277 return false;
278 }
279 break;
280 case Wpa2Psk:
281 if (!interfaceCaps.testFlag(NetworkManager::WirelessDevice::Rsn)) {
282 return false;
283 }
284 if (haveAp) {
285 if (adhoc) {
287 return false;
288 }
289 if (apRsn.testFlag(NetworkManager::AccessPoint::PairCcmp) //
291 return true;
292 }
293 } else {
294 if (apRsn.testFlag(NetworkManager::AccessPoint::KeyMgmtPsk)) {
295 if (apRsn.testFlag(NetworkManager::AccessPoint::PairTkip) //
297 return true;
298 }
299 if (apRsn.testFlag(NetworkManager::AccessPoint::PairCcmp) //
301 return true;
302 }
303 }
304 }
305 return false;
306 }
307 break;
308 case WpaEap:
309 if (adhoc) {
310 return false;
311 }
312 if (!interfaceCaps.testFlag(NetworkManager::WirelessDevice::Wpa)) {
313 return false;
314 }
315 if (haveAp) {
316 if (!apWpa.testFlag(NetworkManager::AccessPoint::KeyMgmt8021x)) {
317 return false;
318 }
319 /* Ensure at least one WPA cipher is supported */
320 if (!deviceSupportsApCiphers(interfaceCaps, apWpa, WpaEap)) {
321 return false;
322 }
323 }
324 break;
325 case Wpa2Eap:
326 if (adhoc) {
327 return false;
328 }
329 if (!interfaceCaps.testFlag(NetworkManager::WirelessDevice::Rsn)) {
330 return false;
331 }
332 if (haveAp) {
333 if (!apRsn.testFlag(NetworkManager::AccessPoint::KeyMgmt8021x)) {
334 return false;
335 }
336 /* Ensure at least one WPA cipher is supported */
337 if (!deviceSupportsApCiphers(interfaceCaps, apRsn, Wpa2Eap)) {
338 return false;
339 }
340 }
341 break;
342 case SAE:
343 if (!interfaceCaps.testFlag(NetworkManager::WirelessDevice::Rsn)) {
344 return false;
345 }
346 if (haveAp) {
347 if (adhoc) {
349 return false;
350 }
351 if (apRsn.testFlag(NetworkManager::AccessPoint::PairCcmp) //
353 return true;
354 }
355 } else {
356 if (apRsn.testFlag(NetworkManager::AccessPoint::KeyMgmtSAE)) {
357 if (apRsn.testFlag(NetworkManager::AccessPoint::PairTkip) //
359 return true;
360 }
361 if (apRsn.testFlag(NetworkManager::AccessPoint::PairCcmp) //
363 return true;
364 }
365 }
366 }
367 return false;
368 }
369 break;
370 case Wpa3SuiteB192:
371 if (adhoc) {
372 return false;
373 }
374 if (!interfaceCaps.testFlag(NetworkManager::WirelessDevice::Rsn)) {
375 return false;
376 }
377 if (haveAp && !apRsn.testFlag(NetworkManager::AccessPoint::KeyMgmtEapSuiteB192)) {
378 return false;
379 }
380 break;
381 default:
382 good = false;
383 break;
384 }
385
386 return good;
387}
388
389NetworkManager::WirelessSecurityType NetworkManager::findBestWirelessSecurity(NetworkManager::WirelessDevice::Capabilities interfaceCaps,
390 bool haveAp,
391 bool adHoc,
395{
396 // The ordering of this list is a pragmatic combination of security level and popularity.
397 // Therefore static WEP is before LEAP and Dynamic WEP because there is no way to detect
398 // if an AP is capable of Dynamic WEP and showing Dynamic WEP first would confuse
399 // Static WEP users.
400 const QList<NetworkManager::WirelessSecurityType> types = {NetworkManager::Wpa3SuiteB192,
401 NetworkManager::SAE,
402 NetworkManager::Wpa2Eap,
403 NetworkManager::Wpa2Psk,
404 NetworkManager::WpaEap,
405 NetworkManager::WpaPsk,
406 NetworkManager::StaticWep,
407 NetworkManager::DynamicWep,
408 NetworkManager::Leap,
409 NetworkManager::NoneSecurity};
410
411 for (NetworkManager::WirelessSecurityType type : types) {
412 if (NetworkManager::securityIsValid(type, interfaceCaps, haveAp, adHoc, apCaps, apWpa, apRsn)) {
413 return type;
414 }
415 }
416 return NetworkManager::UnknownSecurity;
417}
418
419bool NetworkManager::wepKeyIsValid(const QString &key, NetworkManager::WirelessSecuritySetting::WepKeyType type)
420{
421 if (key.isEmpty()) {
422 return false;
423 }
424
425 const int keylen = key.length();
426
427 if (type != WirelessSecuritySetting::NotSpecified) {
428 if (type == WirelessSecuritySetting::Hex) {
429 if (keylen == 10 || keylen == 26) {
430 /* Hex key */
431 for (int i = 0; i < keylen; ++i) {
432 if (!(key.at(i).isDigit() || (key.at(i) >= 'A' && key.at(i) <= 'F') || (key.at(i) >= 'a' && key.at(i) <= 'f'))) {
433 return false;
434 }
435 }
436 return true;
437 } else if (keylen == 5 || keylen == 13) {
438 /* ASCII KEY */
439 for (int i = 0; i < keylen; ++i) {
440 if (!key.at(i).isPrint()) {
441 return false;
442 }
443 }
444 return true;
445 }
446
447 return false;
448 } else if (type == WirelessSecuritySetting::Passphrase) {
449 if (!keylen || keylen > 64) {
450 return false;
451 }
452
453 return true;
454 }
455 }
456
457 return false;
458}
459
460bool NetworkManager::wpaPskIsValid(const QString &psk)
461{
462 if (psk.isEmpty()) {
463 return false;
464 }
465
466 const int psklen = psk.length();
467
468 if (psklen < 8 || psklen > 64) {
469 return false;
470 }
471
472 if (psklen == 64) {
473 /* Hex PSK */
474 for (int i = 0; i < psklen; ++i) {
475 if (!psk.at(i).isLetterOrNumber()) {
476 return false;
477 }
478 }
479 }
480
481 return true;
482}
483
484NetworkManager::WirelessSecurityType NetworkManager::securityTypeFromConnectionSetting(const NetworkManager::ConnectionSettings::Ptr &settings)
485{
486 NetworkManager::WirelessSecuritySetting::Ptr wifiSecuritySetting = settings->setting(Setting::WirelessSecurity).dynamicCast<WirelessSecuritySetting>();
487 if (wifiSecuritySetting->keyMgmt() == WirelessSecuritySetting::Wep) {
488 return StaticWep;
489 } else if (wifiSecuritySetting->keyMgmt() == WirelessSecuritySetting::Ieee8021x) {
490 if (wifiSecuritySetting->authAlg() == WirelessSecuritySetting::Leap) {
491 return Leap;
492 } else {
493 return DynamicWep;
494 }
495 } else if (wifiSecuritySetting->keyMgmt() == WirelessSecuritySetting::WpaPsk) {
496 if (wifiSecuritySetting->proto().contains(WirelessSecuritySetting::Wpa) && !wifiSecuritySetting->proto().contains(WirelessSecuritySetting::Rsn)) {
497 return WpaPsk;
498 }
499 return Wpa2Psk;
500 } else if (wifiSecuritySetting->keyMgmt() == WirelessSecuritySetting::WpaEap) {
501 if (wifiSecuritySetting->proto().contains(WirelessSecuritySetting::Wpa) && !wifiSecuritySetting->proto().contains(WirelessSecuritySetting::Rsn)) {
502 return WpaEap;
503 }
504 return Wpa2Eap;
505 } else if (wifiSecuritySetting->keyMgmt() == WirelessSecuritySetting::SAE) {
506 return SAE;
507 } else if (wifiSecuritySetting->keyMgmt() == WirelessSecuritySetting::WpaEapSuiteB192) {
508 return Wpa3SuiteB192;
509 }
510
511 return NoneSecurity;
512}
513
514QList<QPair<int, int>> NetworkManager::getBFreqs()
515{
517
518 freqs.append(QPair<int, int>(1, 2412));
519 freqs.append(QPair<int, int>(2, 2417));
520 freqs.append(QPair<int, int>(3, 2422));
521 freqs.append(QPair<int, int>(4, 2427));
522 freqs.append(QPair<int, int>(5, 2432));
523 freqs.append(QPair<int, int>(6, 2437));
524 freqs.append(QPair<int, int>(7, 2442));
525 freqs.append(QPair<int, int>(8, 2447));
526 freqs.append(QPair<int, int>(9, 2452));
527 freqs.append(QPair<int, int>(10, 2457));
528 freqs.append(QPair<int, int>(11, 2462));
529 freqs.append(QPair<int, int>(12, 2467));
530 freqs.append(QPair<int, int>(13, 2472));
531 freqs.append(QPair<int, int>(14, 2484));
532
533 return freqs;
534}
535
536QList<QPair<int, int>> NetworkManager::getAFreqs()
537{
539
540 freqs.append(QPair<int, int>(7, 5035));
541 freqs.append(QPair<int, int>(8, 5040));
542 freqs.append(QPair<int, int>(9, 5045));
543 freqs.append(QPair<int, int>(11, 5055));
544 freqs.append(QPair<int, int>(12, 5060));
545 freqs.append(QPair<int, int>(16, 5080));
546 freqs.append(QPair<int, int>(34, 5170));
547 freqs.append(QPair<int, int>(36, 5180));
548 freqs.append(QPair<int, int>(38, 5190));
549 freqs.append(QPair<int, int>(40, 5200));
550 freqs.append(QPair<int, int>(42, 5210));
551 freqs.append(QPair<int, int>(44, 5220));
552 freqs.append(QPair<int, int>(46, 5230));
553 freqs.append(QPair<int, int>(48, 5240));
554 freqs.append(QPair<int, int>(52, 5260));
555 freqs.append(QPair<int, int>(56, 5280));
556 freqs.append(QPair<int, int>(60, 5300));
557 freqs.append(QPair<int, int>(64, 5320));
558 freqs.append(QPair<int, int>(100, 5500));
559 freqs.append(QPair<int, int>(104, 5520));
560 freqs.append(QPair<int, int>(108, 5540));
561 freqs.append(QPair<int, int>(112, 5560));
562 freqs.append(QPair<int, int>(116, 5580));
563 freqs.append(QPair<int, int>(120, 5600));
564 freqs.append(QPair<int, int>(124, 5620));
565 freqs.append(QPair<int, int>(128, 5640));
566 freqs.append(QPair<int, int>(132, 5660));
567 freqs.append(QPair<int, int>(136, 5680));
568 freqs.append(QPair<int, int>(140, 5700));
569 freqs.append(QPair<int, int>(149, 5745));
570 freqs.append(QPair<int, int>(153, 5765));
571 freqs.append(QPair<int, int>(157, 5785));
572 freqs.append(QPair<int, int>(161, 5805));
573 freqs.append(QPair<int, int>(165, 5825));
574 freqs.append(QPair<int, int>(183, 4915));
575 freqs.append(QPair<int, int>(184, 4920));
576 freqs.append(QPair<int, int>(185, 4925));
577 freqs.append(QPair<int, int>(187, 4935));
578 freqs.append(QPair<int, int>(188, 4940));
579 freqs.append(QPair<int, int>(189, 4945));
580 freqs.append(QPair<int, int>(192, 4960));
581 freqs.append(QPair<int, int>(196, 4980));
582
583 return freqs;
584}
585
586QDateTime NetworkManager::clockBootTimeToDateTime(qlonglong clockBootime)
587{
588 clockid_t clk_id = CLOCK_BOOTTIME;
589 struct timespec tp;
590 int r;
591
592 // now is used as a point of reference
593 // with the timespec that contains the number of msec since boot
595 r = clock_gettime(clk_id, &tp);
596 if (r == -1 && errno == EINVAL) {
597 clk_id = CLOCK_MONOTONIC;
598 r = clock_gettime(clk_id, &tp);
599 }
600
601 // convert to msecs
602 long now_msecs = tp.tv_sec * 1000 + tp.tv_nsec / 1000000;
603
604 // diff the msecs and construct a QDateTime based on the offset
605 QDateTime res;
606 if (clockBootime > now_msecs) {
607 qlonglong offset = clockBootime - now_msecs;
609 } else {
610 qlonglong offset = now_msecs - clockBootime;
612 }
613
614 return res;
615}
@ Privacy
Access point supports privacy measures.
Definition accesspoint.h:47
@ Rsn
RSN authethication protocol.
@ Ccmp
CCMP encryption cipher.
@ Tkip
TKIP encryption cipher.
@ IBSSRsn
device supports WPA2/RSN in an IBSS network
@ Wpa
WPA authentication protocol.
Type type(const QSqlDatabase &db)
NETWORKMANAGERQT_EXPORT int findChannel(int freq)
Definition utils.cpp:78
NETWORKMANAGERQT_EXPORT QByteArray ipv6AddressFromHostAddress(const QHostAddress &address)
Definition utils.cpp:26
NETWORKMANAGERQT_EXPORT QByteArray macAddressFromString(const QString &s)
Definition utils.cpp:50
NETWORKMANAGERQT_EXPORT QString macAddressAsString(const QByteArray &ba)
Definition utils.cpp:39
NETWORKMANAGERQT_EXPORT QHostAddress ipv6AddressAsHostAddress(const QByteArray &address)
Definition utils.cpp:13
void push_back(char ch)
void reserve(int size)
void resize(int size)
int size() const const
uint toUInt(bool *ok, int base) const const
bool isDigit() const const
bool isLetterOrNumber() const const
bool isPrint() const const
QDateTime currentDateTime()
QDateTime fromMSecsSinceEpoch(qint64 msecs)
qint64 toMSecsSinceEpoch() const const
bool testFlag(Enum flag) const const
QAbstractSocket::NetworkLayerProtocol protocol() const const
void append(const T &value)
const T & at(int i) const const
int size() const const
QStringList split(const QString &sep, QString::SplitBehavior behavior, Qt::CaseSensitivity cs) const const
QString arg(qlonglong a, int fieldWidth, int base, QChar fillChar) const const
const QChar at(int position) const const
bool isEmpty() const const
int length() const const
QString toUpper() const const
QString join(const QString &separator) const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Sun Feb 25 2024 18:38:29 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.