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

KDE's Doxygen guidelines are available online.